From 8954e8a2180d20719b1bb0d4f77081ff03fd9b43 Mon Sep 17 00:00:00 2001 From: Shashank Kumar Date: Tue, 10 Dec 2024 16:05:59 +0530 Subject: [PATCH 01/51] fix(docs): incorrect description for refund api (#6443) Signed-off-by: Shashank Kumar --- api-reference/openapi_spec.json | 2 +- crates/openapi/src/routes/refunds.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 3f3ffc17a183..2dced0998e92 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -1116,7 +1116,7 @@ "Refunds" ], "summary": "Refunds - List", - "description": "Lists all the refunds associated with the merchant or a payment_id if payment_id is not provided", + "description": "Lists all the refunds associated with the merchant, or for a specific payment if payment_id is provided", "operationId": "List all Refunds", "requestBody": { "content": { diff --git a/crates/openapi/src/routes/refunds.rs b/crates/openapi/src/routes/refunds.rs index 4e096e243a82..0ff0891ee54b 100644 --- a/crates/openapi/src/routes/refunds.rs +++ b/crates/openapi/src/routes/refunds.rs @@ -115,7 +115,7 @@ pub async fn refunds_update() {} /// Refunds - List /// -/// Lists all the refunds associated with the merchant or a payment_id if payment_id is not provided +/// Lists all the refunds associated with the merchant, or for a specific payment if payment_id is provided #[utoipa::path( post, path = "/refunds/list", From 8777f41568ebf5373917089d7d42f3b14fb1bf60 Mon Sep 17 00:00:00 2001 From: Suman Maji <77887221+sumanmaji4@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:06:23 +0530 Subject: [PATCH 02/51] feat(connector): [Unifiedauthenticationservice] add Connector Template Code (#6732) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- config/config.example.toml | 1 + config/deployments/integration_test.toml | 1 + config/deployments/production.toml | 1 + config/deployments/sandbox.toml | 1 + config/development.toml | 2 + config/docker_compose.toml | 2 + crates/api_models/src/connector_enums.rs | 2 + crates/common_enums/src/connector_enums.rs | 1 + .../hyperswitch_connectors/src/connectors.rs | 5 +- .../unified_authentication_service.rs | 600 ++++++++++++++++++ .../transformers.rs | 246 +++++++ .../src/default_implementations.rs | 32 + .../src/default_implementations_v2.rs | 22 + crates/hyperswitch_interfaces/src/configs.rs | 1 + crates/router/src/connector.rs | 6 +- .../connector_integration_v2_impls.rs | 3 + crates/router/src/core/payments/flows.rs | 3 + crates/router/src/types/api.rs | 4 +- crates/router/src/types/transformers.rs | 3 + crates/router/tests/connectors/main.rs | 1 + .../router/tests/connectors/sample_auth.toml | 3 + .../unified_authentication_service.rs | 421 ++++++++++++ crates/test_utils/src/connector_auth.rs | 1 + loadtest/config/development.toml | 2 + scripts/add_connector.sh | 2 +- 25 files changed, 1360 insertions(+), 6 deletions(-) create mode 100644 crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs create mode 100644 crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs create mode 100644 crates/router/tests/connectors/unified_authentication_service.rs diff --git a/config/config.example.toml b/config/config.example.toml index 54a3ab3827bd..5aa9e543fb22 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -267,6 +267,7 @@ stripe.base_url_file_upload = "https://files.stripe.com/" trustpay.base_url = "https://test-tpgw.trustpay.eu/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" tsys.base_url = "https://stagegw.transnox.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.sandbox.volt.io/" wellsfargo.base_url = "https://apitest.cybersource.com/" wellsfargopayout.base_url = "https://api-sandbox.wellsfargo.com/" diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index fbf80ced5f17..de8063b10294 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -107,6 +107,7 @@ thunes.base_url = "https://api.limonetikqualif.com/" trustpay.base_url = "https://test-tpgw.trustpay.eu/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" tsys.base_url = "https://stagegw.transnox.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.sandbox.volt.io/" wellsfargo.base_url = "https://apitest.cybersource.com/" wellsfargopayout.base_url = "https://api-sandbox.wellsfargo.com/" diff --git a/config/deployments/production.toml b/config/deployments/production.toml index befd70795d7d..82f9b65b27a7 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -111,6 +111,7 @@ thunes.base_url = "https://api.limonetik.com/" trustpay.base_url = "https://tpgw.trustpay.eu/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" tsys.base_url = "https://gateway.transit-pass.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.volt.io/" wellsfargo.base_url = "https://api.cybersource.com/" wellsfargopayout.base_url = "https://api.wellsfargo.com/" diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 2defc5729cf2..accf2f586afe 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -111,6 +111,7 @@ thunes.base_url = "https://api.limonetikqualif.com/" trustpay.base_url = "https://test-tpgw.trustpay.eu/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" tsys.base_url = "https://stagegw.transnox.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.sandbox.volt.io/" wellsfargo.base_url = "https://apitest.cybersource.com/" wellsfargopayout.base_url = "https://api-sandbox.wellsfargo.com/" diff --git a/config/development.toml b/config/development.toml index 4e3a9b099938..fa577a78e6ad 100644 --- a/config/development.toml +++ b/config/development.toml @@ -165,6 +165,7 @@ cards = [ "thunes", "trustpay", "tsys", + "unified_authentication_service", "volt", "wellsfargo", "wellsfargopayout", @@ -287,6 +288,7 @@ worldpay.base_url = "https://try.access.worldpay.com/" xendit.base_url = "https://api.xendit.co" trustpay.base_url = "https://test-tpgw.trustpay.eu/" tsys.base_url = "https://stagegw.transnox.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.sandbox.volt.io/" wellsfargo.base_url = "https://apitest.cybersource.com/" wellsfargopayout.base_url = "https://api-sandbox.wellsfargo.com/" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index f38da4183b1a..3cc690203e68 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -198,6 +198,7 @@ stripe.base_url_file_upload = "https://files.stripe.com/" trustpay.base_url = "https://test-tpgw.trustpay.eu/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" tsys.base_url = "https://stagegw.transnox.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.sandbox.volt.io/" wellsfargo.base_url = "https://apitest.cybersource.com/" wellsfargopayout.base_url = "https://api-sandbox.wellsfargo.com/" @@ -287,6 +288,7 @@ cards = [ "thunes", "trustpay", "tsys", + "unified_authentication_service", "volt", "wellsfargo", "wellsfargopayout", diff --git a/crates/api_models/src/connector_enums.rs b/crates/api_models/src/connector_enums.rs index 294666f35f80..c70c54f47920 100644 --- a/crates/api_models/src/connector_enums.rs +++ b/crates/api_models/src/connector_enums.rs @@ -123,6 +123,7 @@ pub enum Connector { //Thunes, Trustpay, Tsys, + // UnifiedAuthenticationService, Volt, Wellsfargo, // Wellsfargopayout, @@ -260,6 +261,7 @@ impl Connector { // | Self::Thunes | Self::Trustpay | Self::Tsys + // | Self::UnifiedAuthenticationService | Self::Volt | Self::Wellsfargo // | Self::Wellsfargopayout diff --git a/crates/common_enums/src/connector_enums.rs b/crates/common_enums/src/connector_enums.rs index 421a51205dea..1776ade36661 100644 --- a/crates/common_enums/src/connector_enums.rs +++ b/crates/common_enums/src/connector_enums.rs @@ -120,6 +120,7 @@ pub enum RoutableConnectors { // Thunes // Tsys, Tsys, + // UnifiedAuthenticationService, Volt, Wellsfargo, // Wellsfargopayout, diff --git a/crates/hyperswitch_connectors/src/connectors.rs b/crates/hyperswitch_connectors/src/connectors.rs index 5b7075cd680a..e7ea31ee0e0b 100644 --- a/crates/hyperswitch_connectors/src/connectors.rs +++ b/crates/hyperswitch_connectors/src/connectors.rs @@ -40,6 +40,7 @@ pub mod stax; pub mod taxjar; pub mod thunes; pub mod tsys; +pub mod unified_authentication_service; pub mod volt; pub mod worldline; pub mod worldpay; @@ -57,6 +58,6 @@ pub use self::{ nexixpay::Nexixpay, nomupay::Nomupay, novalnet::Novalnet, payeezy::Payeezy, payu::Payu, powertranz::Powertranz, prophetpay::Prophetpay, rapyd::Rapyd, razorpay::Razorpay, redsys::Redsys, shift4::Shift4, square::Square, stax::Stax, taxjar::Taxjar, thunes::Thunes, - tsys::Tsys, volt::Volt, worldline::Worldline, worldpay::Worldpay, xendit::Xendit, zen::Zen, - zsl::Zsl, + tsys::Tsys, unified_authentication_service::UnifiedAuthenticationService, volt::Volt, + worldline::Worldline, worldpay::Worldpay, xendit::Xendit, zen::Zen, zsl::Zsl, }; diff --git a/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs new file mode 100644 index 000000000000..e85fe5dd7de7 --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs @@ -0,0 +1,600 @@ +pub mod transformers; + +use common_utils::{ + errors::CustomResult, + ext_traits::BytesExt, + request::{Method, Request, RequestBuilder, RequestContent}, + types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector}, +}; +use error_stack::{report, ResultExt}; +use hyperswitch_domain_models::{ + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, 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}, + types::{ + PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData, + RefundSyncRouterData, RefundsRouterData, + }, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + 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), +} + +impl UnifiedAuthenticationService { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMinorUnitForConnector, + } + } +} + +impl api::Payment for UnifiedAuthenticationService {} +impl api::PaymentSession for UnifiedAuthenticationService {} +impl api::ConnectorAccessToken for UnifiedAuthenticationService {} +impl api::MandateSetup for UnifiedAuthenticationService {} +impl api::PaymentAuthorize for UnifiedAuthenticationService {} +impl api::PaymentSync for UnifiedAuthenticationService {} +impl api::PaymentCapture for UnifiedAuthenticationService {} +impl api::PaymentVoid for UnifiedAuthenticationService {} +impl api::Refund for UnifiedAuthenticationService {} +impl api::RefundExecute for UnifiedAuthenticationService {} +impl api::RefundSync for UnifiedAuthenticationService {} +impl api::PaymentToken for UnifiedAuthenticationService {} + +impl ConnectorIntegration + for UnifiedAuthenticationService +{ + // Not Implemented (R) +} + +impl ConnectorCommonExt + for UnifiedAuthenticationService +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 UnifiedAuthenticationService { + fn id(&self) -> &'static str { + "unified_authentication_service" + } + + 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 { + "application/json" + } + + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { + 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, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + let response: unified_authentication_service::UnifiedAuthenticationServiceErrorResponse = + res.response + .parse_struct("UnifiedAuthenticationServiceErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + event_builder.map(|i| i.set_response_body(&response)); + router_env::logger::info!(connector_response=?response); + + Ok(ErrorResponse { + status_code: res.status_code, + code: response.code, + message: response.message, + reason: response.reason, + attempt_status: None, + connector_transaction_id: None, + }) + } +} + +impl ConnectorValidation for UnifiedAuthenticationService { + //TODO: implement functions when support enabled +} + +impl ConnectorIntegration + for UnifiedAuthenticationService +{ + //TODO: implement sessions flow +} + +impl ConnectorIntegration + for UnifiedAuthenticationService +{ +} + +impl ConnectorIntegration + for UnifiedAuthenticationService +{ +} + +impl ConnectorIntegration + for UnifiedAuthenticationService +{ + fn get_headers( + &self, + req: &PaymentsAuthorizeRouterData, + 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: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, + ) -> CustomResult { + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + + let connector_router_data = + unified_authentication_service::UnifiedAuthenticationServiceRouterData::from(( + amount, req, + )); + let connector_req = + unified_authentication_service::UnifiedAuthenticationServicePaymentsRequest::try_from( + &connector_router_data, + )?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsAuthorizeType::get_url( + self, req, connectors, + )?) + .attach_default_headers() + .headers(types::PaymentsAuthorizeType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsAuthorizeType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsAuthorizeRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: unified_authentication_service::UnifiedAuthenticationServicePaymentsResponse = + res.response + .parse_struct("UnifiedAuthenticationService PaymentsAuthorizeResponse") + .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: &PaymentsSyncRouterData, + 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: &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, + 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()) + } + + fn get_request_body( + &self, + _req: &PaymentsCaptureRouterData, + _connectors: &Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + } + + fn build_request( + &self, + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + RequestBuilder::new() + .method(Method::Post) + .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsCaptureType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsCaptureType::get_request_body( + self, req, connectors, + )?) + .build(), + )) + } + + fn handle_response( + &self, + data: &PaymentsCaptureRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: unified_authentication_service::UnifiedAuthenticationServicePaymentsResponse = + res.response + .parse_struct("UnifiedAuthenticationService PaymentsCaptureResponse") + .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 +{ +} + +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, + }) + } + + 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: &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] +impl webhooks::IncomingWebhook for UnifiedAuthenticationService { + 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/transformers.rs b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs new file mode 100644 index 000000000000..6a9347dbeed7 --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs @@ -0,0 +1,246 @@ +use common_enums::enums; +use common_utils::types::StringMinorUnit; +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}, +}; +use hyperswitch_interfaces::errors; +use masking::Secret; +use serde::{Deserialize, Serialize}; + +use crate::{ + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::PaymentsAuthorizeRequestData, +}; + +//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 router_data: T, +} + +impl From<(StringMinorUnit, T)> for UnifiedAuthenticationServiceRouterData { + fn from((amount, item): (StringMinorUnit, T)) -> Self { + //Todo : use utils to convert the amount to the type of amount that a connector accepts + Self { + amount, + router_data: item, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct UnifiedAuthenticationServicePaymentsRequest { + amount: StringMinorUnit, + card: UnifiedAuthenticationServiceCard, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct UnifiedAuthenticationServiceCard { + number: cards::CardNumber, + expiry_month: Secret, + expiry_year: Secret, + cvc: Secret, + complete: bool, +} + +impl TryFrom<&UnifiedAuthenticationServiceRouterData<&PaymentsAuthorizeRouterData>> + for UnifiedAuthenticationServicePaymentsRequest +{ + type Error = error_stack::Report; + fn try_from( + item: &UnifiedAuthenticationServiceRouterData<&PaymentsAuthorizeRouterData>, + ) -> 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()), + } + } +} + +//TODO: Fill the struct with respective fields +// Auth Struct +pub struct UnifiedAuthenticationServiceAuthType { + pub(super) api_key: Secret, +} + +impl TryFrom<&ConnectorAuthType> for UnifiedAuthenticationServiceAuthType { + type Error = error_stack::Report; + fn try_from(auth_type: &ConnectorAuthType) -> Result { + match auth_type { + ConnectorAuthType::HeaderKey { api_key } => Ok(Self { + api_key: api_key.to_owned(), + }), + _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), + } + } +} +// 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, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct UnifiedAuthenticationServicePaymentsResponse { + status: UnifiedAuthenticationServicePaymentStatus, + id: String, +} + +impl + TryFrom< + ResponseRouterData< + F, + UnifiedAuthenticationServicePaymentsResponse, + T, + PaymentsResponseData, + >, + > for RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: ResponseRouterData< + F, + UnifiedAuthenticationServicePaymentsResponse, + T, + PaymentsResponseData, + >, + ) -> 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, + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +// REFUND : +// Type definition for RefundRequest +#[derive(Default, Debug, Serialize)] +pub struct UnifiedAuthenticationServiceRefundRequest { + pub amount: StringMinorUnit, +} + +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(), + }) + } +} + +// Type definition for Refund Response + +#[allow(dead_code)] +#[derive(Debug, Serialize, Default, Deserialize, Clone)] +pub enum RefundStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +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 + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct RefundResponse { + id: String, + status: RefundStatus, +} + +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; + fn try_from( + item: RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.id.to_string(), + refund_status: enums::RefundStatus::from(item.response.status), + }), + ..item.data + }) + } +} + +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; + fn try_from( + item: RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.id.to_string(), + refund_status: enums::RefundStatus::from(item.response.status), + }), + ..item.data + }) + } +} + +//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, +} diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs index b39f50bfe18f..aaaeecb50e6c 100644 --- a/crates/hyperswitch_connectors/src/default_implementations.rs +++ b/crates/hyperswitch_connectors/src/default_implementations.rs @@ -128,6 +128,7 @@ default_imp_for_authorize_session_token!( connectors::Shift4, connectors::Stax, connectors::Taxjar, + connectors::UnifiedAuthenticationService, connectors::Volt, connectors::Thunes, connectors::Tsys, @@ -194,6 +195,7 @@ default_imp_for_calculate_tax!( connectors::Square, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Volt, connectors::Worldline, connectors::Worldpay, @@ -251,6 +253,7 @@ default_imp_for_session_update!( connectors::Nexixpay, connectors::Payeezy, connectors::Payu, + connectors::UnifiedAuthenticationService, connectors::Fiuu, connectors::Globepay, connectors::Gocardless, @@ -326,6 +329,7 @@ default_imp_for_post_session_tokens!( connectors::Prophetpay, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Deutschebank, connectors::Volt, connectors::Zen, @@ -382,6 +386,7 @@ default_imp_for_complete_authorize!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Xendit, @@ -447,6 +452,7 @@ default_imp_for_incremental_authorization!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -511,6 +517,7 @@ default_imp_for_create_customer!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -574,6 +581,7 @@ default_imp_for_connector_redirect_response!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Xendit, @@ -634,6 +642,7 @@ default_imp_for_pre_processing_steps!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -700,6 +709,7 @@ default_imp_for_post_processing_steps!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -766,6 +776,7 @@ default_imp_for_approve!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -832,6 +843,7 @@ default_imp_for_reject!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -898,6 +910,7 @@ default_imp_for_webhook_source_verification!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -965,6 +978,7 @@ default_imp_for_accept_dispute!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1031,6 +1045,7 @@ default_imp_for_submit_evidence!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1097,6 +1112,7 @@ default_imp_for_defend_dispute!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1172,6 +1188,7 @@ default_imp_for_file_upload!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1230,6 +1247,7 @@ default_imp_for_payouts!( connectors::Stax, connectors::Taxjar, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Volt, connectors::Worldline, connectors::Worldpay, @@ -1298,6 +1316,7 @@ default_imp_for_payouts_create!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1366,6 +1385,7 @@ default_imp_for_payouts_retrieve!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1434,6 +1454,7 @@ default_imp_for_payouts_eligibility!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1502,6 +1523,7 @@ default_imp_for_payouts_fulfill!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1570,6 +1592,7 @@ default_imp_for_payouts_cancel!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1638,6 +1661,7 @@ default_imp_for_payouts_quote!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1706,6 +1730,7 @@ default_imp_for_payouts_recipient!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1774,6 +1799,7 @@ default_imp_for_payouts_recipient_account!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1842,6 +1868,7 @@ default_imp_for_frm_sale!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1910,6 +1937,7 @@ default_imp_for_frm_checkout!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -1978,6 +2006,7 @@ default_imp_for_frm_transaction!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -2046,6 +2075,7 @@ default_imp_for_frm_fulfillment!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -2114,6 +2144,7 @@ default_imp_for_frm_record_return!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, @@ -2179,6 +2210,7 @@ default_imp_for_revoking_mandates!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Worldpay, connectors::Volt, diff --git a/crates/hyperswitch_connectors/src/default_implementations_v2.rs b/crates/hyperswitch_connectors/src/default_implementations_v2.rs index 60e14ca35957..10a5fea8c401 100644 --- a/crates/hyperswitch_connectors/src/default_implementations_v2.rs +++ b/crates/hyperswitch_connectors/src/default_implementations_v2.rs @@ -247,6 +247,7 @@ default_imp_for_new_connector_integration_payment!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -314,6 +315,7 @@ default_imp_for_new_connector_integration_refund!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -376,6 +378,7 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -444,6 +447,7 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -511,6 +515,7 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -578,6 +583,7 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -655,6 +661,7 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -724,6 +731,7 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -793,6 +801,7 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -862,6 +871,7 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -931,6 +941,7 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1000,6 +1011,7 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1069,6 +1081,7 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1138,6 +1151,7 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1207,6 +1221,7 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1274,6 +1289,7 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1343,6 +1359,7 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1412,6 +1429,7 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1481,6 +1499,7 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1550,6 +1569,7 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1619,6 +1639,7 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, @@ -1685,6 +1706,7 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Taxjar, connectors::Thunes, connectors::Tsys, + connectors::UnifiedAuthenticationService, connectors::Worldline, connectors::Volt, connectors::Worldpay, diff --git a/crates/hyperswitch_interfaces/src/configs.rs b/crates/hyperswitch_interfaces/src/configs.rs index d6e195bbec40..e7e59d2d0637 100644 --- a/crates/hyperswitch_interfaces/src/configs.rs +++ b/crates/hyperswitch_interfaces/src/configs.rs @@ -88,6 +88,7 @@ pub struct Connectors { pub thunes: ConnectorParams, pub trustpay: ConnectorParamsWithMoreUrls, pub tsys: ConnectorParams, + pub unified_authentication_service: ConnectorParams, pub volt: ConnectorParams, pub wellsfargo: ConnectorParams, pub wellsfargopayout: ConnectorParams, diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index 1f67c1f75d76..04e972e51871 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -53,8 +53,10 @@ pub use hyperswitch_connectors::connectors::{ payu::Payu, 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, volt, volt::Volt, worldline, worldline::Worldline, worldpay, worldpay::Worldpay, - xendit, xendit::Xendit, zen, zen::Zen, zsl, zsl::Zsl, + tsys::Tsys, unified_authentication_service, + unified_authentication_service::UnifiedAuthenticationService, volt, volt::Volt, worldline, + worldline::Worldline, worldpay, worldpay::Worldpay, xendit, xendit::Xendit, zen, zen::Zen, zsl, + zsl::Zsl, }; #[cfg(feature = "dummy_connector")] 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 7aeca55592a1..286680062f88 100644 --- a/crates/router/src/core/payments/connector_integration_v2_impls.rs +++ b/crates/router/src/core/payments/connector_integration_v2_impls.rs @@ -1145,6 +1145,7 @@ default_imp_for_new_connector_integration_payouts!( connector::Threedsecureio, connector::Thunes, connector::Tsys, + connector::UnifiedAuthenticationService, connector::Volt, connector::Wellsfargo, connector::Wise, @@ -1747,6 +1748,7 @@ default_imp_for_new_connector_integration_frm!( connector::Threedsecureio, connector::Thunes, connector::Tsys, + connector::UnifiedAuthenticationService, connector::Volt, connector::Wellsfargo, connector::Wise, @@ -2214,6 +2216,7 @@ default_imp_for_new_connector_integration_connector_authentication!( connector::Threedsecureio, connector::Thunes, connector::Tsys, + connector::UnifiedAuthenticationService, connector::Volt, connector::Wellsfargo, connector::Wise, diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index cf349ef6e05d..00001e0e6c02 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -508,6 +508,7 @@ default_imp_for_connector_request_id!( connector::Threedsecureio, connector::Trustpay, connector::Tsys, + connector::UnifiedAuthenticationService, connector::Volt, connector::Wellsfargo, connector::Wellsfargopayout, @@ -1711,6 +1712,7 @@ default_imp_for_fraud_check!( connector::Threedsecureio, connector::Trustpay, connector::Tsys, + connector::UnifiedAuthenticationService, connector::Volt, connector::Wellsfargo, connector::Wellsfargopayout, @@ -2341,6 +2343,7 @@ default_imp_for_connector_authentication!( connector::Taxjar, connector::Trustpay, connector::Tsys, + connector::UnifiedAuthenticationService, connector::Volt, connector::Wellsfargo, connector::Wellsfargopayout, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 763d408d174b..661c557e20c8 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -528,7 +528,9 @@ impl ConnectorData { Ok(ConnectorEnum::Old(Box::new(connector::Trustpay::new()))) } enums::Connector::Tsys => Ok(ConnectorEnum::Old(Box::new(connector::Tsys::new()))), - + // enums::Connector::UnifiedAuthenticationService => Ok(ConnectorEnum::Old(Box::new( + // connector::UnifiedAuthenticationService, + // ))), enums::Connector::Volt => Ok(ConnectorEnum::Old(Box::new(connector::Volt::new()))), enums::Connector::Wellsfargo => { Ok(ConnectorEnum::Old(Box::new(connector::Wellsfargo::new()))) diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 55a523b528eb..a3c3da0462a7 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -299,6 +299,9 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { // api_enums::Connector::Thunes => Self::Thunes, api_enums::Connector::Trustpay => Self::Trustpay, api_enums::Connector::Tsys => Self::Tsys, + // api_enums::Connector::UnifiedAuthenticationService => { + // Self::UnifiedAuthenticationService + // } api_enums::Connector::Volt => Self::Volt, api_enums::Connector::Wellsfargo => Self::Wellsfargo, // api_enums::Connector::Wellsfargopayout => Self::Wellsfargopayout, diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs index dcedb171675a..31ceb1a72456 100644 --- a/crates/router/tests/connectors/main.rs +++ b/crates/router/tests/connectors/main.rs @@ -82,6 +82,7 @@ mod stripe; mod taxjar; mod trustpay; mod tsys; +mod unified_authentication_service; mod utils; mod volt; mod wellsfargo; diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index d099c16254b0..f2f849731d52 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -300,4 +300,7 @@ api_key="API Key" api_key="API Key" [nomupay] +api_key="API Key" + +[unified_authentication_service] api_key="API Key" \ No newline at end of file diff --git a/crates/router/tests/connectors/unified_authentication_service.rs b/crates/router/tests/connectors/unified_authentication_service.rs new file mode 100644 index 000000000000..0a403d9d260b --- /dev/null +++ b/crates/router/tests/connectors/unified_authentication_service.rs @@ -0,0 +1,421 @@ +use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData}; +use masking::Secret; +use router::types::{self, api, storage::enums}; +use test_utils::connector_auth; + +use crate::utils::{self, ConnectorActions}; + +#[derive(Clone, Copy)] +struct UnifiedAuthenticationServiceTest; +impl ConnectorActions for UnifiedAuthenticationServiceTest {} +impl utils::Connector for UnifiedAuthenticationServiceTest { + fn get_data(&self) -> api::ConnectorData { + use router::connector::UnifiedAuthenticationService; + utils::construct_connector_data_old( + Box::new(UnifiedAuthenticationService::new()), + types::Connector::Plaid, + api::GetToken::Connector, + None, + ) + } + + fn get_auth_token(&self) -> types::ConnectorAuthType { + utils::to_connector_auth_type( + connector_auth::ConnectorAuthentication::new() + .unified_authentication_service + .expect("Missing connector authentication configuration") + .into(), + ) + } + + fn get_name(&self) -> String { + "unified_authentication_service".to_string() + } +} + +static CONNECTOR: UnifiedAuthenticationServiceTest = UnifiedAuthenticationServiceTest {}; + +fn get_default_payment_info() -> Option { + None +} + +fn payment_method_details() -> Option { + None +} + +// Cards Positive Tests +// Creates a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_only_authorize_payment() { + let response = CONNECTOR + .authorize_payment(payment_method_details(), get_default_payment_info()) + .await + .expect("Authorize payment response"); + assert_eq!(response.status, enums::AttemptStatus::Authorized); +} + +// Captures a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_capture_authorized_payment() { + let response = CONNECTOR + .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info()) + .await + .expect("Capture payment response"); + assert_eq!(response.status, enums::AttemptStatus::Charged); +} + +// Partially captures a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_capture_authorized_payment() { + let response = CONNECTOR + .authorize_and_capture_payment( + payment_method_details(), + Some(types::PaymentsCaptureData { + amount_to_capture: 50, + ..utils::PaymentCaptureType::default().0 + }), + get_default_payment_info(), + ) + .await + .expect("Capture payment response"); + assert_eq!(response.status, enums::AttemptStatus::Charged); +} + +// Synchronizes a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_authorized_payment() { + let authorize_response = CONNECTOR + .authorize_payment(payment_method_details(), get_default_payment_info()) + .await + .expect("Authorize payment response"); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + let response = CONNECTOR + .psync_retry_till_status_matches( + enums::AttemptStatus::Authorized, + Some(types::PaymentsSyncData { + connector_transaction_id: types::ResponseId::ConnectorTransactionId( + txn_id.unwrap(), + ), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .expect("PSync response"); + assert_eq!(response.status, enums::AttemptStatus::Authorized,); +} + +// Voids a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_void_authorized_payment() { + let response = CONNECTOR + .authorize_and_void_payment( + payment_method_details(), + Some(types::PaymentsCancelData { + connector_transaction_id: String::from(""), + cancellation_reason: Some("requested_by_customer".to_string()), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .expect("Void payment response"); + assert_eq!(response.status, enums::AttemptStatus::Voided); +} + +// Refunds a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_manually_captured_payment() { + let response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Partially refunds a payment using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_refund_manually_captured_payment() { + let response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Synchronizes a refund using the manual capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_manually_captured_refund() { + let refund_response = CONNECTOR + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + let response = CONNECTOR + .rsync_retry_till_status_matches( + enums::RefundStatus::Success, + refund_response.response.unwrap().connector_refund_id, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Creates a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_make_payment() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); +} + +// Synchronizes a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_auto_captured_payment() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + assert_ne!(txn_id, None, "Empty connector transaction id"); + let response = CONNECTOR + .psync_retry_till_status_matches( + enums::AttemptStatus::Charged, + Some(types::PaymentsSyncData { + connector_transaction_id: types::ResponseId::ConnectorTransactionId( + txn_id.unwrap(), + ), + capture_method: Some(enums::CaptureMethod::Automatic), + ..Default::default() + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!(response.status, enums::AttemptStatus::Charged,); +} + +// Refunds a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_auto_captured_payment() { + let response = CONNECTOR + .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Partially refunds a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_partially_refund_succeeded_payment() { + let refund_response = CONNECTOR + .make_payment_and_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + refund_response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_refund_succeeded_payment_multiple_times() { + CONNECTOR + .make_payment_and_multiple_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 50, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await; +} + +// Synchronizes a refund using the automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_sync_refund() { + let refund_response = CONNECTOR + .make_payment_and_refund(payment_method_details(), None, get_default_payment_info()) + .await + .unwrap(); + let response = CONNECTOR + .rsync_retry_till_status_matches( + enums::RefundStatus::Success, + refund_response.response.unwrap().connector_refund_id, + None, + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap().refund_status, + enums::RefundStatus::Success, + ); +} + +// Cards Negative scenarios +// Creates a payment with incorrect CVC. +#[actix_web::test] +async fn should_fail_payment_for_incorrect_cvc() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_cvc: Secret::new("12345".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's security code is invalid.".to_string(), + ); +} + +// Creates a payment with incorrect expiry month. +#[actix_web::test] +async fn should_fail_payment_for_invalid_exp_month() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_exp_month: Secret::new("20".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's expiration month is invalid.".to_string(), + ); +} + +// Creates a payment with incorrect expiry year. +#[actix_web::test] +async fn should_fail_payment_for_incorrect_expiry_year() { + let response = CONNECTOR + .make_payment( + Some(types::PaymentsAuthorizeData { + payment_method_data: PaymentMethodData::Card(Card { + card_exp_year: Secret::new("2000".to_string()), + ..utils::CCardType::default().0 + }), + ..utils::PaymentAuthorizeType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Your card's expiration year is invalid.".to_string(), + ); +} + +// Voids a payment using automatic capture flow (Non 3DS). +#[actix_web::test] +async fn should_fail_void_payment_for_auto_capture() { + let authorize_response = CONNECTOR + .make_payment(payment_method_details(), get_default_payment_info()) + .await + .unwrap(); + assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); + let txn_id = utils::get_connector_transaction_id(authorize_response.response); + assert_ne!(txn_id, None, "Empty connector transaction id"); + let void_response = CONNECTOR + .void_payment(txn_id.unwrap(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + void_response.response.unwrap_err().message, + "You cannot cancel this PaymentIntent because it has a status of succeeded." + ); +} + +// Captures a payment using invalid connector payment id. +#[actix_web::test] +async fn should_fail_capture_for_invalid_payment() { + let capture_response = CONNECTOR + .capture_payment("123456789".to_string(), None, get_default_payment_info()) + .await + .unwrap(); + assert_eq!( + capture_response.response.unwrap_err().message, + String::from("No such payment_intent: '123456789'") + ); +} + +// Refunds a payment with refund amount higher than payment amount. +#[actix_web::test] +async fn should_fail_for_refund_amount_higher_than_payment_amount() { + let response = CONNECTOR + .make_payment_and_refund( + payment_method_details(), + Some(types::RefundsData { + refund_amount: 150, + ..utils::PaymentRefundType::default().0 + }), + get_default_payment_info(), + ) + .await + .unwrap(); + assert_eq!( + response.response.unwrap_err().message, + "Refund amount (₹1.50) is greater than charge amount (₹1.00)", + ); +} + +// Connector dependent test cases goes here + +// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests diff --git a/crates/test_utils/src/connector_auth.rs b/crates/test_utils/src/connector_auth.rs index 3fab02e64d19..37cc341c4540 100644 --- a/crates/test_utils/src/connector_auth.rs +++ b/crates/test_utils/src/connector_auth.rs @@ -89,6 +89,7 @@ pub struct ConnectorAuthentication { pub stripe_uk: Option, pub trustpay: Option, pub tsys: Option, + pub unified_authentication_service: Option, pub volt: Option, pub wellsfargo: Option, // pub wellsfargopayout: Option, diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index 81bcf01fddc1..51981a298e31 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -164,6 +164,7 @@ stripe.base_url_file_upload = "https://files.stripe.com/" trustpay.base_url = "https://test-tpgw.trustpay.eu/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" tsys.base_url = "https://stagegw.transnox.com/" +unified_authentication_service.base_url = "http://localhost:8000" volt.base_url = "https://api.sandbox.volt.io/" wellsfargo.base_url = "https://apitest.cybersource.com/" wellsfargopayout.base_url = "https://api-sandbox.wellsfargo.com/" @@ -252,6 +253,7 @@ cards = [ "thunes", "trustpay", "tsys", + "unified_authentication_service", "volt", "wellsfargo", "wellsfargopayout", diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh index fd555a416135..108e9d882635 100755 --- a/scripts/add_connector.sh +++ b/scripts/add_connector.sh @@ -6,7 +6,7 @@ function find_prev_connector() { git checkout $self cp $self $self.tmp # Add new connector to existing list and sort it - connectors=(aci adyen adyenplatform airwallex amazonpay applepay authorizedotnet bambora bamboraapac bankofamerica billwerk bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource datatrans deutschebank digitalvirgo dlocal dummyconnector ebanx elavon fiserv fiservemea fiuu forte globalpay globepay gocardless gpayments helcim iatapay inespay itaubank jpmorgan klarna mifinity mollie multisafepay netcetera nexinets nexixpay nomupay noon novalnet nuvei opayo opennode paybox payeezy payme payone paypal payu placetopay plaid powertranz prophetpay rapyd razorpay redsys shift4 square stax stripe taxjar threedsecureio thunes trustpay tsys volt wellsfargo wellsfargopayout wise worldline worldpay xendit zsl "$1") + connectors=(aci adyen adyenplatform airwallex amazonpay applepay authorizedotnet bambora bamboraapac bankofamerica billwerk bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource datatrans deutschebank digitalvirgo dlocal dummyconnector ebanx elavon fiserv fiservemea fiuu forte globalpay globepay gocardless gpayments helcim iatapay inespay itaubank jpmorgan klarna mifinity mollie multisafepay netcetera nexinets nexixpay nomupay noon novalnet nuvei opayo opennode paybox payeezy payme payone paypal payu placetopay plaid powertranz prophetpay rapyd razorpay redsys shift4 square stax stripe taxjar threedsecureio thunes trustpay tsys unified_authentication_service volt wellsfargo wellsfargopayout wise worldline worldpay xendit zsl "$1") IFS=$'\n' sorted=($(sort <<<"${connectors[*]}")); unset IFS res="$(echo ${sorted[@]})" sed -i'' -e "s/^ connectors=.*/ connectors=($res \"\$1\")/" $self.tmp From 6f841458f73cec8ce43a34b1b50abbc74baa2ef7 Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:09:46 +0530 Subject: [PATCH 03/51] refactor(payment_methods): Add new field_type UserBsbNumber, UserBankSortCode and UserBankRoutingNumber for payment_connector_required_fields (#6758) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- api-reference-v2/openapi_spec.json | 18 ++++++++++++++++++ api-reference/openapi_spec.json | 18 ++++++++++++++++++ crates/api_models/src/enums.rs | 3 +++ .../payment_connector_required_fields.rs | 12 ++++++------ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 64949c3812b6..2cd5467f06eb 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -8583,6 +8583,24 @@ "user_iban" ] }, + { + "type": "string", + "enum": [ + "user_bsb_number" + ] + }, + { + "type": "string", + "enum": [ + "user_bank_sort_code" + ] + }, + { + "type": "string", + "enum": [ + "user_bank_routing_number" + ] + }, { "type": "string", "enum": [ diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 2dced0998e92..937dc7ab2d9a 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -10925,6 +10925,24 @@ "user_iban" ] }, + { + "type": "string", + "enum": [ + "user_bsb_number" + ] + }, + { + "type": "string", + "enum": [ + "user_bank_sort_code" + ] + }, + { + "type": "string", + "enum": [ + "user_bank_routing_number" + ] + }, { "type": "string", "enum": [ diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 4af3f855d77b..4275b10fd814 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -223,6 +223,9 @@ pub enum FieldType { UserCpf, UserCnpj, UserIban, + UserBsbNumber, + UserBankSortCode, + UserBankRoutingNumber, UserMsisdn, UserClientIdentifier, OrderDetailsProductName, diff --git a/crates/router/src/configs/defaults/payment_connector_required_fields.rs b/crates/router/src/configs/defaults/payment_connector_required_fields.rs index c759b724414a..0954ac51c7df 100644 --- a/crates/router/src/configs/defaults/payment_connector_required_fields.rs +++ b/crates/router/src/configs/defaults/payment_connector_required_fields.rs @@ -11634,7 +11634,7 @@ impl Default for settings::RequiredFields { RequiredFieldInfo { required_field: "payment_method_data.bank_debit.ach_bank_debit.routing_number".to_string(), display_name: "bank_routing_number".to_string(), - field_type: enums::FieldType::Text, + field_type: enums::FieldType::UserBankRoutingNumber, value: None, } ) @@ -11676,7 +11676,7 @@ impl Default for settings::RequiredFields { RequiredFieldInfo { required_field: "payment_method_data.bank_debit.ach_bank_debit.routing_number".to_string(), display_name: "bank_routing_number".to_string(), - field_type: enums::FieldType::Text, + field_type: enums::FieldType::UserBankRoutingNumber, value: None, } ) @@ -11845,7 +11845,7 @@ impl Default for settings::RequiredFields { RequiredFieldInfo { required_field: "payment_method_data.bank_debit.bacs_bank_debit.sort_code".to_string(), display_name: "bank_sort_code".to_string(), - field_type: enums::FieldType::Text, + field_type: enums::FieldType::UserBankSortCode, value: None, } ), @@ -11917,7 +11917,7 @@ impl Default for settings::RequiredFields { RequiredFieldInfo { required_field: "payment_method_data.bank_debit.bacs_bank_debit.sort_code".to_string(), display_name: "bank_sort_code".to_string(), - field_type: enums::FieldType::Text, + field_type: enums::FieldType::UserBankSortCode, value: None, } ) @@ -11967,7 +11967,7 @@ impl Default for settings::RequiredFields { RequiredFieldInfo { required_field: "payment_method_data.bank_debit.becs_bank_debit.bsb_number".to_string(), display_name: "bsb_number".to_string(), - field_type: enums::FieldType::Text, + field_type: enums::FieldType::UserBsbNumber, value: None, } ), @@ -12019,7 +12019,7 @@ impl Default for settings::RequiredFields { RequiredFieldInfo { required_field: "payment_method_data.bank_debit.becs_bank_debit.sort_code".to_string(), display_name: "bank_sort_code".to_string(), - field_type: enums::FieldType::Text, + field_type: enums::FieldType::UserBankSortCode, value: None, } ) From b9c04c39880aa1ab0b66397802d138f0d4c1ed28 Mon Sep 17 00:00:00 2001 From: GORAKHNATH YADAV Date: Tue, 10 Dec 2024 16:28:45 +0530 Subject: [PATCH 04/51] docs: add new logos for README and API reference (#6783) --- api-reference-v2/logo/dark.svg | 48 ++++++++++++---------------- api-reference-v2/logo/light.svg | 48 ++++++++++++---------------- api-reference/logo/dark.svg | 30 +++++++++++------ api-reference/logo/light.svg | 30 +++++++++++------ docs/imgs/hyperswitch-logo-dark.svg | 30 +++++++++++------ docs/imgs/hyperswitch-logo-light.svg | 30 +++++++++++------ 6 files changed, 120 insertions(+), 96 deletions(-) diff --git a/api-reference-v2/logo/dark.svg b/api-reference-v2/logo/dark.svg index fbf0d89d4106..f07be0cea141 100644 --- a/api-reference-v2/logo/dark.svg +++ b/api-reference-v2/logo/dark.svg @@ -1,29 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/api-reference-v2/logo/light.svg b/api-reference-v2/logo/light.svg index c951a909dd49..66b2c279d06f 100644 --- a/api-reference-v2/logo/light.svg +++ b/api-reference-v2/logo/light.svg @@ -1,29 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/api-reference/logo/dark.svg b/api-reference/logo/dark.svg index c54a55785e86..f07be0cea141 100644 --- a/api-reference/logo/dark.svg +++ b/api-reference/logo/dark.svg @@ -1,11 +1,21 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/api-reference/logo/light.svg b/api-reference/logo/light.svg index 03f45e271424..66b2c279d06f 100644 --- a/api-reference/logo/light.svg +++ b/api-reference/logo/light.svg @@ -1,11 +1,21 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/docs/imgs/hyperswitch-logo-dark.svg b/docs/imgs/hyperswitch-logo-dark.svg index c54a55785e86..f07be0cea141 100644 --- a/docs/imgs/hyperswitch-logo-dark.svg +++ b/docs/imgs/hyperswitch-logo-dark.svg @@ -1,11 +1,21 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/docs/imgs/hyperswitch-logo-light.svg b/docs/imgs/hyperswitch-logo-light.svg index 03f45e271424..66b2c279d06f 100644 --- a/docs/imgs/hyperswitch-logo-light.svg +++ b/docs/imgs/hyperswitch-logo-light.svg @@ -1,11 +1,21 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + From a52828296a682e30badf0849921469cdf4eecbea Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 10 Dec 2024 16:33:31 +0530 Subject: [PATCH 05/51] refactor(enums): recon - include ReconOps variant in PermissionsGroup for backwards compatibility with data in DB (#6767) --- crates/common_enums/src/enums.rs | 5 ++--- crates/router/src/services/authorization/info.rs | 2 +- .../router/src/services/authorization/permission_groups.rs | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 23e2f285cf34..88c3b6846781 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -2828,10 +2828,9 @@ pub enum PermissionGroup { ReconReportsView, ReconReportsManage, ReconOpsView, - // Alias is added for backward compatibility with database - // TODO: Remove alias post migration - #[serde(alias = "recon_ops")] ReconOpsManage, + // TODO: To be deprecated, make sure DB is migrated before removing + ReconOps, } #[derive(Clone, Debug, serde::Serialize, PartialEq, Eq, Hash, strum::EnumIter)] diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs index 2d808a4377ae..e02838b3e000 100644 --- a/crates/router/src/services/authorization/info.rs +++ b/crates/router/src/services/authorization/info.rs @@ -43,7 +43,7 @@ fn get_group_description(group: PermissionGroup) -> &'static str { PermissionGroup::ReconReportsView => "View and access reconciliation reports and analytics", PermissionGroup::ReconReportsManage => "Manage reconciliation reports", PermissionGroup::ReconOpsView => "View and access reconciliation operations", - PermissionGroup::ReconOpsManage => "Manage reconciliation operations", + PermissionGroup::ReconOpsManage | PermissionGroup::ReconOps => "Manage reconciliation operations", } } diff --git a/crates/router/src/services/authorization/permission_groups.rs b/crates/router/src/services/authorization/permission_groups.rs index 8c45210e4b53..14eda547e883 100644 --- a/crates/router/src/services/authorization/permission_groups.rs +++ b/crates/router/src/services/authorization/permission_groups.rs @@ -33,6 +33,7 @@ impl PermissionGroupExt for PermissionGroup { | Self::OrganizationManage | Self::AccountManage | Self::ReconOpsManage + | Self::ReconOps | Self::ReconReportsManage => PermissionScope::Write, } } @@ -49,7 +50,7 @@ impl PermissionGroupExt for PermissionGroup { | Self::MerchantDetailsManage | Self::AccountView | Self::AccountManage => ParentGroup::Account, - Self::ReconOpsView | Self::ReconOpsManage => ParentGroup::ReconOps, + Self::ReconOpsView | Self::ReconOpsManage | Self::ReconOps => ParentGroup::ReconOps, Self::ReconReportsView | Self::ReconReportsManage => ParentGroup::ReconReports, } } @@ -81,7 +82,7 @@ impl PermissionGroupExt for PermissionGroup { } Self::ReconOpsView => vec![Self::ReconOpsView], - Self::ReconOpsManage => vec![Self::ReconOpsView, Self::ReconOpsManage], + Self::ReconOpsManage | Self::ReconOps => vec![Self::ReconOpsView, Self::ReconOpsManage], Self::ReconReportsView => vec![Self::ReconReportsView], Self::ReconReportsManage => vec![Self::ReconReportsView, Self::ReconReportsManage], From 47a3d2b2abcc28a13f79bd9318d119f103b7fb6c Mon Sep 17 00:00:00 2001 From: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:35:34 +0530 Subject: [PATCH 06/51] build(deps): bump opentelemetry crates to 0.27 (#6774) --- Cargo.lock | 273 +++++------------- config/loki.yaml | 4 +- config/otel-collector.yaml | 7 +- crates/analytics/src/api_event/core.rs | 7 +- crates/analytics/src/disputes/core.rs | 7 +- crates/analytics/src/frm/core.rs | 7 +- crates/analytics/src/metrics.rs | 5 +- crates/analytics/src/metrics/request.rs | 8 +- crates/analytics/src/payment_intents/core.rs | 7 +- crates/analytics/src/payments/core.rs | 13 +- crates/analytics/src/refunds/core.rs | 13 +- crates/common_utils/src/id_type/merchant.rs | 5 +- crates/common_utils/src/id_type/payment.rs | 5 +- crates/common_utils/src/id_type/profile.rs | 8 + crates/common_utils/src/metrics/utils.rs | 3 +- crates/diesel_models/src/lib.rs | 5 +- crates/diesel_models/src/query/generics.rs | 18 +- crates/drainer/src/handler.rs | 22 +- crates/drainer/src/logger.rs | 2 +- crates/drainer/src/main.rs | 4 +- crates/drainer/src/metrics.rs | 16 +- crates/drainer/src/query.rs | 41 +-- crates/drainer/src/stream.rs | 6 +- crates/drainer/src/utils.rs | 4 +- crates/external_services/src/aws_kms/core.rs | 8 +- crates/external_services/src/lib.rs | 7 +- .../src/connectors/boku.rs | 9 +- crates/hyperswitch_connectors/src/metrics.rs | 3 +- crates/hyperswitch_connectors/src/utils.rs | 9 +- .../src/type_encryption.rs | 59 ++-- crates/hyperswitch_interfaces/src/api.rs | 4 +- .../src/connector_integration_v2.rs | 8 +- crates/hyperswitch_interfaces/src/metrics.rs | 3 +- crates/router/src/core/admin.rs | 8 +- crates/router/src/core/api_keys.rs | 13 +- crates/router/src/core/customers.rs | 4 +- crates/router/src/core/disputes.rs | 14 +- crates/router/src/core/mandate.rs | 11 +- crates/router/src/core/metrics.rs | 4 +- .../router/src/core/payment_methods/cards.rs | 38 +-- .../payment_methods/network_tokenization.rs | 7 +- .../router/src/core/payment_methods/vault.rs | 23 +- crates/router/src/core/payments.rs | 24 +- .../router/src/core/payments/access_token.rs | 16 +- crates/router/src/core/payments/customers.rs | 5 +- .../src/core/payments/flows/authorize_flow.rs | 14 +- .../src/core/payments/flows/cancel_flow.rs | 4 +- .../payments/flows/complete_authorize_flow.rs | 6 +- .../src/core/payments/flows/session_flow.rs | 4 +- crates/router/src/core/payments/helpers.rs | 42 ++- .../payments/operations/payment_response.rs | 17 +- crates/router/src/core/payments/retry.rs | 10 +- .../router/src/core/payments/tokenization.rs | 7 +- .../router/src/core/payments/transformers.rs | 9 +- .../router/src/core/payouts/access_token.rs | 4 +- crates/router/src/core/payouts/helpers.rs | 4 +- crates/router/src/core/payouts/retry.rs | 14 +- crates/router/src/core/refunds.rs | 33 +-- crates/router/src/core/routing.rs | 86 +++--- crates/router/src/core/routing/helpers.rs | 24 +- crates/router/src/core/utils.rs | 6 +- crates/router/src/core/webhooks/incoming.rs | 49 ++-- .../router/src/core/webhooks/incoming_v2.rs | 35 +-- crates/router/src/core/webhooks/outgoing.rs | 32 +- crates/router/src/routes/health.rs | 4 +- crates/router/src/routes/metrics.rs | 25 +- crates/router/src/routes/metrics/request.rs | 18 +- crates/router/src/services/api.rs | 52 ++-- crates/router/src/services/authentication.rs | 2 +- .../src/services/authentication/decision.rs | 15 +- crates/router/src/utils.rs | 70 ++--- crates/router/src/utils/db_utils.rs | 4 +- crates/router/src/workflows/api_key_expiry.rs | 9 +- crates/router_env/Cargo.toml | 10 +- crates/router_env/src/logger/setup.rs | 230 ++++++++------- crates/router_env/src/metrics.rs | 137 +++++---- crates/scheduler/src/consumer.rs | 4 +- crates/scheduler/src/db/process_tracker.rs | 4 +- crates/scheduler/src/metrics.rs | 5 +- crates/scheduler/src/producer.rs | 2 +- crates/scheduler/src/utils.rs | 14 +- crates/storage_impl/src/lib.rs | 4 +- crates/storage_impl/src/metrics.rs | 3 +- crates/storage_impl/src/redis/cache.rs | 29 +- crates/storage_impl/src/redis/kv_store.rs | 11 +- crates/storage_impl/src/utils.rs | 2 +- 86 files changed, 737 insertions(+), 1084 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8315e8049a6..c8d5fc4cecc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1429,34 +1429,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes 1.7.1", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.5" @@ -1464,7 +1436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", - "axum-core 0.4.3", + "axum-core", "bytes 1.7.1", "futures-util", "http 1.1.0", @@ -1484,23 +1456,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes 1.7.1", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.3" @@ -3164,12 +3119,12 @@ dependencies = [ "lettre", "masking", "once_cell", - "prost 0.13.2", + "prost", "router_env", "serde", "thiserror", "tokio 1.40.0", - "tonic 0.12.2", + "tonic", "tonic-build", "tonic-reflection", "tonic-types", @@ -3953,18 +3908,6 @@ dependencies = [ "tokio-rustls 0.24.1", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.30", - "pin-project-lite", - "tokio 1.40.0", - "tokio-io-timeout", -] - [[package]] name = "hyper-timeout" version = "0.5.1" @@ -5052,9 +4995,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "mutually_exclusive_features" -version = "0.0.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d02c0b00610773bb7fc61d85e13d86c7858cbdf00e1a120bfc41bc055dbaa0e" +checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" [[package]] name = "nanoid" @@ -5417,76 +5360,72 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.19.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" +checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7" dependencies = [ - "opentelemetry_api", + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror", + "tracing", +] + +[[package]] +name = "opentelemetry-aws" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eacb6bb0b662955ba69d788c979462b079e70903e29867c2303cc1305ec8de" +dependencies = [ + "once_cell", + "opentelemetry", "opentelemetry_sdk", + "tracing", ] [[package]] name = "opentelemetry-otlp" -version = "0.12.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af72d59a4484654ea8eb183fea5ae4eb6a41d7ac3e3bae5f4d2a282a3a7d3ca" +checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" dependencies = [ "async-trait", - "futures 0.3.30", - "futures-util", - "http 0.2.12", + "futures-core", + "http 1.1.0", "opentelemetry", "opentelemetry-proto", - "prost 0.11.9", + "opentelemetry_sdk", + "prost", "thiserror", "tokio 1.40.0", - "tonic 0.8.3", + "tonic", ] [[package]] name = "opentelemetry-proto" -version = "0.2.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045f8eea8c0fa19f7d48e7bc3128a39c2e5c533d5c61298c548dfefc1064474c" +checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" dependencies = [ - "futures 0.3.30", - "futures-util", "opentelemetry", - "prost 0.11.9", - "tonic 0.8.3", -] - -[[package]] -name = "opentelemetry_api" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" -dependencies = [ - "fnv", - "futures-channel", - "futures-util", - "indexmap 1.9.3", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", + "opentelemetry_sdk", + "prost", + "tonic", ] [[package]] name = "opentelemetry_sdk" -version = "0.19.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" +checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" dependencies = [ "async-trait", - "crossbeam-channel", - "dashmap", - "fnv", "futures-channel", "futures-executor", "futures-util", - "once_cell", - "opentelemetry_api", + "glob", + "opentelemetry", "percent-encoding", "rand", "thiserror", @@ -6015,16 +5954,6 @@ dependencies = [ "unarray", ] -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes 1.7.1", - "prost-derive 0.11.9", -] - [[package]] name = "prost" version = "0.13.2" @@ -6032,7 +5961,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes 1.7.1", - "prost-derive 0.13.2", + "prost-derive", ] [[package]] @@ -6049,26 +5978,13 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost 0.13.2", + "prost", "prost-types", "regex", "syn 2.0.77", "tempfile", ] -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "prost-derive" version = "0.13.2" @@ -6088,7 +6004,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" dependencies = [ - "prost 0.13.2", + "prost", ] [[package]] @@ -6739,7 +6655,9 @@ dependencies = [ "gethostname", "once_cell", "opentelemetry", + "opentelemetry-aws", "opentelemetry-otlp", + "opentelemetry_sdk", "rustc-hash", "serde", "serde_json", @@ -8460,16 +8378,6 @@ dependencies = [ "log", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio 1.40.0", -] - [[package]] name = "tokio-macros" version = "2.4.0" @@ -8544,9 +8452,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -8724,45 +8632,13 @@ dependencies = [ [[package]] name = "tonic" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" -dependencies = [ - "async-stream", - "async-trait", - "axum 0.6.20", - "base64 0.13.1", - "bytes 1.7.1", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "hyper-timeout 0.4.1", - "percent-encoding", - "pin-project", - "prost 0.11.9", - "prost-derive 0.11.9", - "tokio 1.40.0", - "tokio-stream", - "tokio-util", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "tonic" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum 0.7.5", + "axum", "base64 0.22.1", "bytes 1.7.1", "h2 0.4.6", @@ -8770,11 +8646,11 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-timeout 0.5.1", + "hyper-timeout", "hyper-util", "percent-encoding", "pin-project", - "prost 0.13.2", + "prost", "socket2", "tokio 1.40.0", "tokio-stream", @@ -8803,11 +8679,11 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b56b874eedb04f89907573b408eab1e87c1c1dce43aac6ad63742f57faa99ff" dependencies = [ - "prost 0.13.2", + "prost", "prost-types", "tokio 1.40.0", "tokio-stream", - "tonic 0.12.2", + "tonic", ] [[package]] @@ -8816,9 +8692,9 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d967793411bc1a5392accf4731114295f0fd122865d22cde46a8584b03402b2" dependencies = [ - "prost 0.13.2", + "prost", "prost-types", - "tonic 0.12.2", + "tonic", ] [[package]] @@ -8883,9 +8759,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee9e39a66d9b615644893ffc1704d2a89b5b315b7fd0228ad3182ca9a306b19" +checksum = "54a9f5c1aca50ebebf074ee665b9f99f2e84906dcf6b993a0d0090edb835166d" dependencies = [ "actix-web", "mutually_exclusive_features", @@ -8940,17 +8816,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -8964,16 +8829,20 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.19.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600" +checksum = "97a971f6058498b5c0f1affa23e7ea202057a7301dbff68e968b2d578bcbd053" dependencies = [ + "js-sys", "once_cell", "opentelemetry", + "opentelemetry_sdk", + "smallvec 1.13.2", "tracing", "tracing-core", - "tracing-log 0.1.4", + "tracing-log", "tracing-subscriber", + "web-time", ] [[package]] @@ -9003,7 +8872,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", "tracing-serde", ] @@ -9453,6 +9322,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webdriver" version = "0.46.0" diff --git a/config/loki.yaml b/config/loki.yaml index da84e3c3e22d..51b4fa3e40da 100644 --- a/config/loki.yaml +++ b/config/loki.yaml @@ -23,9 +23,9 @@ ingester: schema_config: configs: - from: 2020-10-24 - store: boltdb-shipper + store: tsdb object_store: filesystem - schema: v11 + schema: v13 index: prefix: index_ period: 24h diff --git a/config/otel-collector.yaml b/config/otel-collector.yaml index d7d571c7c87a..9e64dbc4e229 100644 --- a/config/otel-collector.yaml +++ b/config/otel-collector.yaml @@ -2,6 +2,7 @@ receivers: otlp: protocols: grpc: + endpoint: 0.0.0.0:4317 exporters: otlp: @@ -9,8 +10,8 @@ exporters: tls: insecure: true - logging: - loglevel: debug + debug: + verbosity: detailed prometheus: endpoint: 0.0.0.0:8889 @@ -21,7 +22,7 @@ exporters: service: telemetry: logs: - level: debug + level: DEBUG metrics: level: detailed address: 0.0.0.0:8888 diff --git a/crates/analytics/src/api_event/core.rs b/crates/analytics/src/api_event/core.rs index 425d1476a476..27cc2a4d6975 100644 --- a/crates/analytics/src/api_event/core.rs +++ b/crates/analytics/src/api_event/core.rs @@ -12,7 +12,6 @@ use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; use router_env::{ instrument, logger, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -136,14 +135,14 @@ pub async fn get_api_event_metrics( .change_context(AnalyticsError::UnknownError)? { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_type", metric.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } for (id, value) in data { diff --git a/crates/analytics/src/disputes/core.rs b/crates/analytics/src/disputes/core.rs index f4235518b2d2..540a14104c1f 100644 --- a/crates/analytics/src/disputes/core.rs +++ b/crates/analytics/src/disputes/core.rs @@ -11,7 +11,6 @@ use api_models::analytics::{ use error_stack::ResultExt; use router_env::{ logger, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -72,14 +71,14 @@ pub async fn get_metrics( .change_context(AnalyticsError::UnknownError)? { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_type", metric.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } diff --git a/crates/analytics/src/frm/core.rs b/crates/analytics/src/frm/core.rs index 6f120913a7a4..195266b4191a 100644 --- a/crates/analytics/src/frm/core.rs +++ b/crates/analytics/src/frm/core.rs @@ -9,7 +9,6 @@ use api_models::analytics::{ use error_stack::ResultExt; use router_env::{ logger, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -66,13 +65,13 @@ pub async fn get_metrics( { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_type", metric.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } diff --git a/crates/analytics/src/metrics.rs b/crates/analytics/src/metrics.rs index 6222315a8c06..03eab289333d 100644 --- a/crates/analytics/src/metrics.rs +++ b/crates/analytics/src/metrics.rs @@ -1,9 +1,8 @@ -use router_env::{global_meter, histogram_metric, histogram_metric_u64, metrics_context}; +use router_env::{global_meter, histogram_metric_f64, histogram_metric_u64}; -metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); -histogram_metric!(METRIC_FETCH_TIME, GLOBAL_METER); +histogram_metric_f64!(METRIC_FETCH_TIME, GLOBAL_METER); histogram_metric_u64!(BUCKETS_FETCHED, GLOBAL_METER); pub mod request; diff --git a/crates/analytics/src/metrics/request.rs b/crates/analytics/src/metrics/request.rs index 39375d391a3e..c30e34da8ee2 100644 --- a/crates/analytics/src/metrics/request.rs +++ b/crates/analytics/src/metrics/request.rs @@ -1,7 +1,5 @@ use std::time; -use router_env::metrics::add_attributes; - #[inline] pub async fn record_operation_time( future: F, @@ -14,12 +12,12 @@ where T: ToString, { let (result, time) = time_future(future).await; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_name", metric_name.to_string()), ("source", source.to_string()), - ]); + ); let value = time.as_secs_f64(); - metric.record(&super::CONTEXT, value, attributes); + metric.record(value, attributes); router_env::logger::debug!("Attributes: {:?}, Time: {}", attributes, value); result diff --git a/crates/analytics/src/payment_intents/core.rs b/crates/analytics/src/payment_intents/core.rs index 80cfc5630710..00a59d82870c 100644 --- a/crates/analytics/src/payment_intents/core.rs +++ b/crates/analytics/src/payment_intents/core.rs @@ -16,7 +16,6 @@ use currency_conversion::{conversion::convert, types::ExchangeRates}; use error_stack::ResultExt; use router_env::{ instrument, logger, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -118,14 +117,14 @@ pub async fn get_metrics( match task_type { TaskType::MetricTask(metric, data) => { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_type", metric.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs index c6f0276c47f4..86192265d072 100644 --- a/crates/analytics/src/payments/core.rs +++ b/crates/analytics/src/payments/core.rs @@ -16,7 +16,6 @@ use currency_conversion::{conversion::convert, types::ExchangeRates}; use error_stack::ResultExt; use router_env::{ instrument, logger, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -126,14 +125,14 @@ pub async fn get_metrics( match task_type { TaskType::MetricTask(metric, data) => { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_type", metric.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } @@ -193,14 +192,14 @@ pub async fn get_metrics( } TaskType::DistributionTask(distribution, data) => { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("distribution_type", distribution.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } diff --git a/crates/analytics/src/refunds/core.rs b/crates/analytics/src/refunds/core.rs index ca72c9003a6e..04badd06bd2d 100644 --- a/crates/analytics/src/refunds/core.rs +++ b/crates/analytics/src/refunds/core.rs @@ -16,7 +16,6 @@ use currency_conversion::{conversion::convert, types::ExchangeRates}; use error_stack::ResultExt; use router_env::{ logger, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -121,14 +120,14 @@ pub async fn get_metrics( match task_type { TaskType::MetricTask(metric, data) => { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("metric_type", metric.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } @@ -168,13 +167,13 @@ pub async fn get_metrics( } TaskType::DistributionTask(distribution, data) => { let data = data?; - let attributes = &add_attributes([ + let attributes = router_env::metric_attributes!( ("distribution_type", distribution.to_string()), ("source", pool.to_string()), - ]); + ); let value = u64::try_from(data.len()); if let Ok(val) = value { - metrics::BUCKETS_FETCHED.record(&metrics::CONTEXT, val, attributes); + metrics::BUCKETS_FETCHED.record(val, attributes); logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val); } diff --git a/crates/common_utils/src/id_type/merchant.rs b/crates/common_utils/src/id_type/merchant.rs index 08b80249ae34..e12f71e917f9 100644 --- a/crates/common_utils/src/id_type/merchant.rs +++ b/crates/common_utils/src/id_type/merchant.rs @@ -30,12 +30,11 @@ crate::impl_serializable_secret_id_type!(MerchantId); crate::impl_queryable_id_type!(MerchantId); crate::impl_to_sql_from_sql_id_type!(MerchantId); +// This is implemented so that we can use merchant id directly as attribute in metrics #[cfg(feature = "metrics")] -/// This is implemented so that we can use merchant id directly as attribute in metrics impl From for router_env::opentelemetry::Value { fn from(val: MerchantId) -> Self { - let string_value = val.0 .0 .0; - Self::String(router_env::opentelemetry::StringValue::from(string_value)) + Self::from(val.0 .0 .0) } } diff --git a/crates/common_utils/src/id_type/payment.rs b/crates/common_utils/src/id_type/payment.rs index 60bc9968f312..33bf9d241707 100644 --- a/crates/common_utils/src/id_type/payment.rs +++ b/crates/common_utils/src/id_type/payment.rs @@ -79,11 +79,10 @@ crate::impl_try_from_cow_str_id_type!(PaymentReferenceId, "payment_reference_id" crate::impl_queryable_id_type!(PaymentReferenceId); crate::impl_to_sql_from_sql_id_type!(PaymentReferenceId); +// This is implemented so that we can use payment id directly as attribute in metrics #[cfg(feature = "metrics")] -/// This is implemented so that we can use payment id directly as attribute in metrics impl From for router_env::opentelemetry::Value { fn from(val: PaymentId) -> Self { - let string_value = val.0 .0 .0; - Self::String(router_env::opentelemetry::StringValue::from(string_value)) + Self::from(val.0 .0 .0) } } diff --git a/crates/common_utils/src/id_type/profile.rs b/crates/common_utils/src/id_type/profile.rs index a73cdfdd5392..9e1733a84143 100644 --- a/crates/common_utils/src/id_type/profile.rs +++ b/crates/common_utils/src/id_type/profile.rs @@ -31,3 +31,11 @@ impl FromStr for ProfileId { Self::try_from(cow_string) } } + +// This is implemented so that we can use profile id directly as attribute in metrics +#[cfg(feature = "metrics")] +impl From for router_env::opentelemetry::Value { + fn from(val: ProfileId) -> Self { + Self::from(val.0 .0 .0) + } +} diff --git a/crates/common_utils/src/metrics/utils.rs b/crates/common_utils/src/metrics/utils.rs index 71244ecc4fe4..c1f2ef8f985b 100644 --- a/crates/common_utils/src/metrics/utils.rs +++ b/crates/common_utils/src/metrics/utils.rs @@ -21,13 +21,12 @@ where pub async fn record_operation_time( future: F, metric: &opentelemetry::metrics::Histogram, - metric_context: &opentelemetry::Context, key_value: &[opentelemetry::KeyValue], ) -> R where F: futures::Future, { let (result, time) = time_future(future).await; - metric.record(metric_context, time.as_secs_f64(), key_value); + metric.record(time.as_secs_f64(), key_value); result } diff --git a/crates/diesel_models/src/lib.rs b/crates/diesel_models/src/lib.rs index d07f84aa65e2..cc3dc1361545 100644 --- a/crates/diesel_models/src/lib.rs +++ b/crates/diesel_models/src/lib.rs @@ -128,11 +128,10 @@ pub(crate) mod diesel_impl { } pub(crate) mod metrics { - use router_env::{counter_metric, global_meter, histogram_metric, metrics_context, once_cell}; + use router_env::{counter_metric, global_meter, histogram_metric_f64, once_cell}; - metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); counter_metric!(DATABASE_CALLS_COUNT, GLOBAL_METER); - histogram_metric!(DATABASE_CALL_TIME, GLOBAL_METER); + histogram_metric_f64!(DATABASE_CALL_TIME, GLOBAL_METER); } diff --git a/crates/diesel_models/src/query/generics.rs b/crates/diesel_models/src/query/generics.rs index 682766679fd7..bf3238ab4fea 100644 --- a/crates/diesel_models/src/query/generics.rs +++ b/crates/diesel_models/src/query/generics.rs @@ -25,8 +25,6 @@ use router_env::logger; use crate::{errors, PgPooledConn, StorageResult}; pub mod db_metrics { - use router_env::opentelemetry::KeyValue; - #[derive(Debug)] pub enum DatabaseOperation { FindOne, @@ -51,18 +49,14 @@ pub mod db_metrics { let table_name = std::any::type_name::().rsplit("::").nth(1); - let attributes = [ - KeyValue::new("table", table_name.unwrap_or("undefined")), - KeyValue::new("operation", format!("{:?}", operation)), - ]; - - crate::metrics::DATABASE_CALLS_COUNT.add(&crate::metrics::CONTEXT, 1, &attributes); - crate::metrics::DATABASE_CALL_TIME.record( - &crate::metrics::CONTEXT, - time_elapsed.as_secs_f64(), - &attributes, + let attributes = router_env::metric_attributes!( + ("table", table_name.unwrap_or("undefined")), + ("operation", format!("{:?}", operation)) ); + crate::metrics::DATABASE_CALLS_COUNT.add(1, attributes); + crate::metrics::DATABASE_CALL_TIME.record(time_elapsed.as_secs_f64(), attributes); + output } } diff --git a/crates/drainer/src/handler.rs b/crates/drainer/src/handler.rs index d0c26195453b..74984b03fbd2 100644 --- a/crates/drainer/src/handler.rs +++ b/crates/drainer/src/handler.rs @@ -74,7 +74,7 @@ impl Handler { let jobs_picked = Arc::new(atomic::AtomicU8::new(0)); while self.running.load(atomic::Ordering::SeqCst) { - metrics::DRAINER_HEALTH.add(&metrics::CONTEXT, 1, &[]); + metrics::DRAINER_HEALTH.add(1, &[]); for store in self.stores.values() { if store.is_stream_available(stream_index).await { let _task_handle = tokio::spawn( @@ -103,7 +103,7 @@ impl Handler { pub(crate) async fn shutdown_listener(&self, mut rx: mpsc::Receiver<()>) { while let Some(_c) = rx.recv().await { logger::info!("Awaiting shutdown!"); - metrics::SHUTDOWN_SIGNAL_RECEIVED.add(&metrics::CONTEXT, 1, &[]); + metrics::SHUTDOWN_SIGNAL_RECEIVED.add(1, &[]); let shutdown_started = time::Instant::now(); rx.close(); @@ -112,9 +112,9 @@ impl Handler { time::sleep(self.shutdown_interval).await; } logger::info!("Terminating drainer"); - metrics::SUCCESSFUL_SHUTDOWN.add(&metrics::CONTEXT, 1, &[]); + metrics::SUCCESSFUL_SHUTDOWN.add(1, &[]); let shutdown_ended = shutdown_started.elapsed().as_secs_f64() * 1000f64; - metrics::CLEANUP_TIME.record(&metrics::CONTEXT, shutdown_ended, &[]); + metrics::CLEANUP_TIME.record(shutdown_ended, &[]); self.close(); } logger::info!( @@ -217,7 +217,7 @@ async fn drainer( if let redis_interface::errors::RedisError::StreamEmptyOrNotAvailable = redis_err.current_context() { - metrics::STREAM_EMPTY.add(&metrics::CONTEXT, 1, &[]); + metrics::STREAM_EMPTY.add(1, &[]); return Ok(()); } else { return Err(error); @@ -236,12 +236,8 @@ async fn drainer( let read_count = entries.len(); metrics::JOBS_PICKED_PER_STREAM.add( - &metrics::CONTEXT, u64::try_from(read_count).unwrap_or(u64::MIN), - &[metrics::KeyValue { - key: "stream".into(), - value: stream_name.to_string().into(), - }], + router_env::metric_attributes!(("stream", stream_name.to_owned())), ); let session_id = common_utils::generate_id_with_default_len("drainer_session"); @@ -254,12 +250,8 @@ async fn drainer( Err(err) => { logger::error!(operation = "deserialization", err=?err); metrics::STREAM_PARSE_FAIL.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue { - key: "operation".into(), - value: "deserialization".into(), - }], + router_env::metric_attributes!(("operation", "deserialization")), ); // break from the loop in case of a deser error diff --git a/crates/drainer/src/logger.rs b/crates/drainer/src/logger.rs index b23b0ab2675d..8044b0462d94 100644 --- a/crates/drainer/src/logger.rs +++ b/crates/drainer/src/logger.rs @@ -1,2 +1,2 @@ #[doc(inline)] -pub use router_env::*; +pub use router_env::{debug, error, info, warn}; diff --git a/crates/drainer/src/main.rs b/crates/drainer/src/main.rs index c5a4a39f95d4..91ec191bf9f2 100644 --- a/crates/drainer/src/main.rs +++ b/crates/drainer/src/main.rs @@ -1,8 +1,6 @@ use std::collections::HashMap; -use drainer::{ - errors::DrainerResult, logger::logger, services, settings, start_drainer, start_web_server, -}; +use drainer::{errors::DrainerResult, logger, services, settings, start_drainer, start_web_server}; use router_env::tracing::Instrument; #[tokio::main] diff --git a/crates/drainer/src/metrics.rs b/crates/drainer/src/metrics.rs index 750f23bc73b5..13fb31f7c500 100644 --- a/crates/drainer/src/metrics.rs +++ b/crates/drainer/src/metrics.rs @@ -1,9 +1,5 @@ -pub use router_env::opentelemetry::KeyValue; -use router_env::{ - counter_metric, global_meter, histogram_metric, histogram_metric_i64, metrics_context, -}; +use router_env::{counter_metric, global_meter, histogram_metric_f64, histogram_metric_u64}; -metrics_context!(CONTEXT); global_meter!(DRAINER_METER, "DRAINER"); counter_metric!(JOBS_PICKED_PER_STREAM, DRAINER_METER); @@ -17,8 +13,8 @@ counter_metric!(STREAM_EMPTY, DRAINER_METER); counter_metric!(STREAM_PARSE_FAIL, DRAINER_METER); counter_metric!(DRAINER_HEALTH, DRAINER_METER); -histogram_metric!(QUERY_EXECUTION_TIME, DRAINER_METER); // Time in (ms) milliseconds -histogram_metric!(REDIS_STREAM_READ_TIME, DRAINER_METER); // Time in (ms) milliseconds -histogram_metric!(REDIS_STREAM_TRIM_TIME, DRAINER_METER); // Time in (ms) milliseconds -histogram_metric!(CLEANUP_TIME, DRAINER_METER); // Time in (ms) milliseconds -histogram_metric_i64!(DRAINER_DELAY_SECONDS, DRAINER_METER); // Time in (s) seconds +histogram_metric_f64!(QUERY_EXECUTION_TIME, DRAINER_METER); // Time in (ms) milliseconds +histogram_metric_f64!(REDIS_STREAM_READ_TIME, DRAINER_METER); // Time in (ms) milliseconds +histogram_metric_f64!(REDIS_STREAM_TRIM_TIME, DRAINER_METER); // Time in (ms) milliseconds +histogram_metric_f64!(CLEANUP_TIME, DRAINER_METER); // Time in (ms) milliseconds +histogram_metric_u64!(DRAINER_DELAY_SECONDS, DRAINER_METER); // Time in (s) seconds diff --git a/crates/drainer/src/query.rs b/crates/drainer/src/query.rs index a1e04fb6d0f1..ec6b271aa9da 100644 --- a/crates/drainer/src/query.rs +++ b/crates/drainer/src/query.rs @@ -25,32 +25,23 @@ impl ExecuteQuery for kv::DBOperation { let operation = self.operation(); let table = self.table(); - let tags: &[metrics::KeyValue] = &[ - metrics::KeyValue { - key: "operation".into(), - value: operation.into(), - }, - metrics::KeyValue { - key: "table".into(), - value: table.into(), - }, - ]; + let tags = router_env::metric_attributes!(("operation", operation), ("table", table)); let (result, execution_time) = Box::pin(common_utils::date_time::time_it(|| self.execute(&conn))).await; push_drainer_delay(pushed_at, operation, table, tags); - metrics::QUERY_EXECUTION_TIME.record(&metrics::CONTEXT, execution_time, tags); + metrics::QUERY_EXECUTION_TIME.record(execution_time, tags); match result { Ok(result) => { logger::info!(operation = operation, table = table, ?result); - metrics::SUCCESSFUL_QUERY_EXECUTION.add(&metrics::CONTEXT, 1, tags); + metrics::SUCCESSFUL_QUERY_EXECUTION.add(1, tags); Ok(()) } Err(err) => { logger::error!(operation = operation, table = table, ?err); - metrics::ERRORS_WHILE_QUERY_EXECUTION.add(&metrics::CONTEXT, 1, tags); + metrics::ERRORS_WHILE_QUERY_EXECUTION.add(1, tags); Err(err) } } @@ -58,15 +49,25 @@ impl ExecuteQuery for kv::DBOperation { } #[inline(always)] -fn push_drainer_delay(pushed_at: i64, operation: &str, table: &str, tags: &[metrics::KeyValue]) { +fn push_drainer_delay( + pushed_at: i64, + operation: &str, + table: &str, + tags: &[router_env::opentelemetry::KeyValue], +) { let drained_at = common_utils::date_time::now_unix_timestamp(); let delay = drained_at - pushed_at; - logger::debug!( - operation = operation, - table = table, - delay = format!("{delay} secs") - ); + logger::debug!(operation, table, delay = format!("{delay} secs")); - metrics::DRAINER_DELAY_SECONDS.record(&metrics::CONTEXT, delay, tags); + match u64::try_from(delay) { + Ok(delay) => metrics::DRAINER_DELAY_SECONDS.record(delay, tags), + Err(error) => logger::error!( + pushed_at, + drained_at, + delay, + ?error, + "Invalid drainer delay" + ), + } } diff --git a/crates/drainer/src/stream.rs b/crates/drainer/src/stream.rs index 319fc2b0e1d3..f5b41c536727 100644 --- a/crates/drainer/src/stream.rs +++ b/crates/drainer/src/stream.rs @@ -69,9 +69,8 @@ impl Store { .await; metrics::REDIS_STREAM_READ_TIME.record( - &metrics::CONTEXT, execution_time, - &[metrics::KeyValue::new("stream", stream_name.to_owned())], + router_env::metric_attributes!(("stream", stream_name.to_owned())), ); Ok(output?) @@ -104,9 +103,8 @@ impl Store { .await; metrics::REDIS_STREAM_TRIM_TIME.record( - &metrics::CONTEXT, execution_time, - &[metrics::KeyValue::new("stream", stream_name.to_owned())], + router_env::metric_attributes!(("stream", stream_name.to_owned())), ); // adding 1 because we are deleting the given id too diff --git a/crates/drainer/src/utils.rs b/crates/drainer/src/utils.rs index c8c6e312f14b..72f12c60492a 100644 --- a/crates/drainer/src/utils.rs +++ b/crates/drainer/src/utils.rs @@ -63,8 +63,8 @@ pub async fn increment_stream_index( ) -> u8 { if index == total_streams - 1 { match jobs_picked.load(atomic::Ordering::SeqCst) { - 0 => metrics::CYCLES_COMPLETED_UNSUCCESSFULLY.add(&metrics::CONTEXT, 1, &[]), - _ => metrics::CYCLES_COMPLETED_SUCCESSFULLY.add(&metrics::CONTEXT, 1, &[]), + 0 => metrics::CYCLES_COMPLETED_UNSUCCESSFULLY.add(1, &[]), + _ => metrics::CYCLES_COMPLETED_SUCCESSFULLY.add(1, &[]), } jobs_picked.store(0, atomic::Ordering::SeqCst); 0 diff --git a/crates/external_services/src/aws_kms/core.rs b/crates/external_services/src/aws_kms/core.rs index 8ffd631b819c..537e63655b5b 100644 --- a/crates/external_services/src/aws_kms/core.rs +++ b/crates/external_services/src/aws_kms/core.rs @@ -63,7 +63,7 @@ impl AwsKmsClient { // Logging using `Debug` representation of the error as the `Display` // representation does not hold sufficient information. logger::error!(aws_kms_sdk_error=?error, "Failed to AWS KMS decrypt data"); - metrics::AWS_KMS_DECRYPTION_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::AWS_KMS_DECRYPTION_FAILURES.add(1, &[]); }) .change_context(AwsKmsError::DecryptionFailed)?; @@ -75,7 +75,7 @@ impl AwsKmsClient { })?; let time_taken = start.elapsed(); - metrics::AWS_KMS_DECRYPT_TIME.record(&metrics::CONTEXT, time_taken.as_secs_f64(), &[]); + metrics::AWS_KMS_DECRYPT_TIME.record(time_taken.as_secs_f64(), &[]); Ok(output) } @@ -99,7 +99,7 @@ impl AwsKmsClient { // Logging using `Debug` representation of the error as the `Display` // representation does not hold sufficient information. logger::error!(aws_kms_sdk_error=?error, "Failed to AWS KMS encrypt data"); - metrics::AWS_KMS_ENCRYPTION_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::AWS_KMS_ENCRYPTION_FAILURES.add(1, &[]); }) .change_context(AwsKmsError::EncryptionFailed)?; @@ -108,7 +108,7 @@ impl AwsKmsClient { .ok_or(AwsKmsError::MissingCiphertextEncryptionOutput) .map(|blob| consts::BASE64_ENGINE.encode(blob.into_inner()))?; let time_taken = start.elapsed(); - metrics::AWS_KMS_ENCRYPT_TIME.record(&metrics::CONTEXT, time_taken.as_secs_f64(), &[]); + metrics::AWS_KMS_ENCRYPT_TIME.record(time_taken.as_secs_f64(), &[]); Ok(output) } diff --git a/crates/external_services/src/lib.rs b/crates/external_services/src/lib.rs index 4570a5e59605..304ce248317a 100644 --- a/crates/external_services/src/lib.rs +++ b/crates/external_services/src/lib.rs @@ -30,9 +30,8 @@ pub mod consts { /// Metrics for interactions with external systems. #[cfg(feature = "aws_kms")] pub mod metrics { - use router_env::{counter_metric, global_meter, histogram_metric, metrics_context}; + use router_env::{counter_metric, global_meter, histogram_metric_f64}; - metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "EXTERNAL_SERVICES"); #[cfg(feature = "aws_kms")] @@ -41,7 +40,7 @@ pub mod metrics { counter_metric!(AWS_KMS_ENCRYPTION_FAILURES, GLOBAL_METER); // No. of AWS KMS Encryption failures #[cfg(feature = "aws_kms")] - histogram_metric!(AWS_KMS_DECRYPT_TIME, GLOBAL_METER); // Histogram for AWS KMS decryption time (in sec) + histogram_metric_f64!(AWS_KMS_DECRYPT_TIME, GLOBAL_METER); // Histogram for AWS KMS decryption time (in sec) #[cfg(feature = "aws_kms")] - histogram_metric!(AWS_KMS_ENCRYPT_TIME, GLOBAL_METER); // Histogram for AWS KMS encryption time (in sec) + histogram_metric_f64!(AWS_KMS_ENCRYPT_TIME, GLOBAL_METER); // Histogram for AWS KMS encryption time (in sec) } diff --git a/crates/hyperswitch_connectors/src/connectors/boku.rs b/crates/hyperswitch_connectors/src/connectors/boku.rs index e6d47c05a91e..73b17ca802ec 100644 --- a/crates/hyperswitch_connectors/src/connectors/boku.rs +++ b/crates/hyperswitch_connectors/src/connectors/boku.rs @@ -38,7 +38,7 @@ use hyperswitch_interfaces::{ }; use masking::{ExposeInterface, Mask, PeekInterface, Secret, WithType}; use ring::hmac; -use router_env::{logger, metrics::add_attributes}; +use router_env::logger; use time::OffsetDateTime; use transformers as boku; @@ -678,11 +678,8 @@ fn get_xml_deserialized( res: Response, event_builder: Option<&mut ConnectorEvent>, ) -> CustomResult { - metrics::CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE.add( - &metrics::CONTEXT, - 1, - &add_attributes([("connector", "boku")]), - ); + metrics::CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE + .add(1, router_env::metric_attributes!(("connector", "boku"))); let response_data = String::from_utf8(res.response.to_vec()) .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; diff --git a/crates/hyperswitch_connectors/src/metrics.rs b/crates/hyperswitch_connectors/src/metrics.rs index 0ce7942663b1..b4e8a2dbd25a 100644 --- a/crates/hyperswitch_connectors/src/metrics.rs +++ b/crates/hyperswitch_connectors/src/metrics.rs @@ -1,8 +1,7 @@ //! Metrics interface -use router_env::{counter_metric, global_meter, metrics_context}; +use router_env::{counter_metric, global_meter}; -metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); counter_metric!(CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE, GLOBAL_METER); diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 408a0282543d..27e80fafa92e 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -34,7 +34,7 @@ use image::Luma; use masking::{ExposeInterface, PeekInterface, Secret}; use once_cell::sync::Lazy; use regex::Regex; -use router_env::{logger, metrics::add_attributes}; +use router_env::logger; use serde::Serializer; use serde_json::Value; @@ -133,11 +133,8 @@ pub(crate) fn handle_json_response_deserialization_failure( res: Response, connector: &'static str, ) -> CustomResult { - crate::metrics::CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE.add( - &crate::metrics::CONTEXT, - 1, - &add_attributes([("connector", connector)]), - ); + crate::metrics::CONNECTOR_RESPONSE_DESERIALIZATION_FAILURE + .add(1, router_env::metric_attributes!(("connector", connector))); let response_data = String::from_utf8(res.response.to_vec()) .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; diff --git a/crates/hyperswitch_domain_models/src/type_encryption.rs b/crates/hyperswitch_domain_models/src/type_encryption.rs index 641e295155fc..07ff1caf7afa 100644 --- a/crates/hyperswitch_domain_models/src/type_encryption.rs +++ b/crates/hyperswitch_domain_models/src/type_encryption.rs @@ -143,7 +143,7 @@ mod encrypt { Ok(response) => Ok(ForeignFrom::foreign_from((masked_data.clone(), response))), Err(err) => { logger::error!("Encryption error {:?}", err); - metrics::ENCRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::ENCRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Encryption"); Self::encrypt(masked_data, key, crypt_algo).await } @@ -187,7 +187,7 @@ mod encrypt { match decrypted { Ok(de) => Ok(de), Err(_) => { - metrics::DECRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::DECRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Decryption"); Self::decrypt(encrypted_data, key, crypt_algo).await } @@ -202,7 +202,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult { - metrics::APPLICATION_ENCRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]); let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?; Ok(Self::new(masked_data, encrypted_data.into())) } @@ -214,7 +214,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult { - metrics::APPLICATION_DECRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]); let encrypted = encrypted_data.into_inner(); let data = crypt_algo.decode_message(key, encrypted.clone())?; @@ -251,7 +251,7 @@ mod encrypt { match result { Ok(response) => Ok(ForeignFrom::foreign_from((masked_data, response))), Err(err) => { - metrics::ENCRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::ENCRYPTION_API_FAILURES.add(1, &[]); logger::error!("Encryption error {:?}", err); logger::info!("Fall back to Application Encryption"); Self::batch_encrypt(masked_data, key, crypt_algo).await @@ -295,7 +295,7 @@ mod encrypt { match decrypted { Ok(de) => Ok(de), Err(_) => { - metrics::DECRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::DECRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Decryption"); Self::batch_decrypt(encrypted_data, key, crypt_algo).await } @@ -310,7 +310,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult, errors::CryptoError> { - metrics::APPLICATION_ENCRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]); masked_data .into_iter() .map(|(k, v)| { @@ -332,7 +332,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult, errors::CryptoError> { - metrics::APPLICATION_DECRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]); encrypted_data .into_iter() .map(|(k, v)| { @@ -380,7 +380,7 @@ mod encrypt { Ok(response) => Ok(ForeignFrom::foreign_from((masked_data.clone(), response))), Err(err) => { logger::error!("Encryption error {:?}", err); - metrics::ENCRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::ENCRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Encryption"); Self::encrypt(masked_data, key, crypt_algo).await } @@ -423,7 +423,7 @@ mod encrypt { match decrypted { Ok(de) => Ok(de), Err(_) => { - metrics::DECRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::DECRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Decryption"); Self::decrypt(encrypted_data, key, crypt_algo).await } @@ -438,7 +438,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult { - metrics::APPLICATION_ENCRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]); let data = serde_json::to_vec(&masked_data.peek()) .change_context(errors::CryptoError::DecodingFailed)?; let encrypted_data = crypt_algo.encode_message(key, &data)?; @@ -452,7 +452,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult { - metrics::APPLICATION_DECRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]); let encrypted = encrypted_data.into_inner(); let data = crypt_algo.decode_message(key, encrypted.clone())?; @@ -487,7 +487,7 @@ mod encrypt { match result { Ok(response) => Ok(ForeignFrom::foreign_from((masked_data, response))), Err(err) => { - metrics::ENCRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::ENCRYPTION_API_FAILURES.add(1, &[]); logger::error!("Encryption error {:?}", err); logger::info!("Fall back to Application Encryption"); Self::batch_encrypt(masked_data, key, crypt_algo).await @@ -531,7 +531,7 @@ mod encrypt { match decrypted { Ok(de) => Ok(de), Err(_) => { - metrics::DECRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::DECRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Decryption"); Self::batch_decrypt(encrypted_data, key, crypt_algo).await } @@ -546,7 +546,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult, errors::CryptoError> { - metrics::APPLICATION_ENCRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]); masked_data .into_iter() .map(|(k, v)| { @@ -567,7 +567,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult, errors::CryptoError> { - metrics::APPLICATION_DECRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]); encrypted_data .into_iter() .map(|(k, v)| { @@ -851,7 +851,7 @@ mod encrypt { Ok(response) => Ok(ForeignFrom::foreign_from((masked_data.clone(), response))), Err(err) => { logger::error!("Encryption error {:?}", err); - metrics::ENCRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::ENCRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Encryption"); Self::encrypt(masked_data, key, crypt_algo).await } @@ -894,7 +894,7 @@ mod encrypt { match decrypted { Ok(de) => Ok(de), Err(_) => { - metrics::DECRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::DECRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Decryption"); Self::decrypt(encrypted_data, key, crypt_algo).await } @@ -909,7 +909,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult { - metrics::APPLICATION_ENCRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]); let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?; Ok(Self::new(masked_data, encrypted_data.into())) } @@ -921,7 +921,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult { - metrics::APPLICATION_DECRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]); let encrypted = encrypted_data.into_inner(); let data = crypt_algo.decode_message(key, encrypted.clone())?; Ok(Self::new(data.into(), encrypted)) @@ -953,7 +953,7 @@ mod encrypt { match result { Ok(response) => Ok(ForeignFrom::foreign_from((masked_data, response))), Err(err) => { - metrics::ENCRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::ENCRYPTION_API_FAILURES.add(1, &[]); logger::error!("Encryption error {:?}", err); logger::info!("Fall back to Application Encryption"); Self::batch_encrypt(masked_data, key, crypt_algo).await @@ -997,7 +997,7 @@ mod encrypt { match decrypted { Ok(de) => Ok(de), Err(_) => { - metrics::DECRYPTION_API_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::DECRYPTION_API_FAILURES.add(1, &[]); logger::info!("Fall back to Application Decryption"); Self::batch_decrypt(encrypted_data, key, crypt_algo).await } @@ -1012,7 +1012,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult, errors::CryptoError> { - metrics::APPLICATION_ENCRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]); masked_data .into_iter() .map(|(k, v)| { @@ -1031,7 +1031,7 @@ mod encrypt { key: &[u8], crypt_algo: V, ) -> CustomResult, errors::CryptoError> { - metrics::APPLICATION_DECRYPTION_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]); encrypted_data .into_iter() .map(|(k, v)| { @@ -1140,7 +1140,6 @@ where record_operation_time( crypto::Encryptable::encrypt_via_api(state, inner, identifier, key, crypto::GcmAes256), &metrics::ENCRYPTION_TIME, - &metrics::CONTEXT, &[], ) .await @@ -1167,7 +1166,6 @@ where crypto::GcmAes256, ), &metrics::ENCRYPTION_TIME, - &metrics::CONTEXT, &[], ) .await @@ -1223,7 +1221,6 @@ where record_operation_time( crypto::Encryptable::decrypt_via_api(state, inner, identifier, key, crypto::GcmAes256), &metrics::DECRYPTION_TIME, - &metrics::CONTEXT, &[], ) .await @@ -1250,7 +1247,6 @@ where crypto::GcmAes256, ), &metrics::ENCRYPTION_TIME, - &metrics::CONTEXT, &[], ) .await @@ -1320,14 +1316,13 @@ where } pub(crate) mod metrics { - use router_env::{counter_metric, global_meter, histogram_metric, metrics_context, once_cell}; + use router_env::{counter_metric, global_meter, histogram_metric_f64, once_cell}; - metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); // Encryption and Decryption metrics - histogram_metric!(ENCRYPTION_TIME, GLOBAL_METER); - histogram_metric!(DECRYPTION_TIME, GLOBAL_METER); + histogram_metric_f64!(ENCRYPTION_TIME, GLOBAL_METER); + histogram_metric_f64!(DECRYPTION_TIME, GLOBAL_METER); counter_metric!(ENCRYPTION_API_FAILURES, GLOBAL_METER); counter_metric!(DECRYPTION_API_FAILURES, GLOBAL_METER); counter_metric!(APPLICATION_ENCRYPTION_COUNT, GLOBAL_METER); diff --git a/crates/hyperswitch_interfaces/src/api.rs b/crates/hyperswitch_interfaces/src/api.rs index 1326444bb475..617832f191df 100644 --- a/crates/hyperswitch_interfaces/src/api.rs +++ b/crates/hyperswitch_interfaces/src/api.rs @@ -35,7 +35,6 @@ use hyperswitch_domain_models::{ router_response_types::{MandateRevokeResponseData, VerifyWebhookSourceResponseData}, }; use masking::Maskable; -use router_env::metrics::add_attributes; use serde_json::json; #[cfg(feature = "payouts")] @@ -121,9 +120,8 @@ pub trait ConnectorIntegration: _connectors: &Connectors, ) -> CustomResult, errors::ConnectorError> { metrics::UNIMPLEMENTED_FLOW.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", req.connector.clone())]), + router_env::metric_attributes!(("connector", req.connector.clone())), ); Ok(None) } diff --git a/crates/hyperswitch_interfaces/src/connector_integration_v2.rs b/crates/hyperswitch_interfaces/src/connector_integration_v2.rs index 9384ed0a0cda..bc18f5c66394 100644 --- a/crates/hyperswitch_interfaces/src/connector_integration_v2.rs +++ b/crates/hyperswitch_interfaces/src/connector_integration_v2.rs @@ -5,7 +5,6 @@ use common_utils::{ }; use hyperswitch_domain_models::{router_data::ErrorResponse, router_data_v2::RouterDataV2}; use masking::Maskable; -use router_env::metrics::add_attributes; use serde_json::json; use crate::{ @@ -65,11 +64,8 @@ pub trait ConnectorIntegrationV2: &self, _req: &RouterDataV2, ) -> CustomResult { - metrics::UNIMPLEMENTED_FLOW.add( - &metrics::CONTEXT, - 1, - &add_attributes([("connector", self.id())]), - ); + metrics::UNIMPLEMENTED_FLOW + .add(1, router_env::metric_attributes!(("connector", self.id()))); Ok(String::new()) } diff --git a/crates/hyperswitch_interfaces/src/metrics.rs b/crates/hyperswitch_interfaces/src/metrics.rs index fc374eba8e24..84aa6d10be09 100644 --- a/crates/hyperswitch_interfaces/src/metrics.rs +++ b/crates/hyperswitch_interfaces/src/metrics.rs @@ -1,8 +1,7 @@ //! Metrics interface -use router_env::{counter_metric, global_meter, metrics_context}; +use router_env::{counter_metric, global_meter}; -metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); counter_metric!(UNIMPLEMENTED_FLOW, GLOBAL_METER); diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 40ed4e755210..8e2145071146 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -20,7 +20,6 @@ use hyperswitch_domain_models::merchant_connector_account::{ use masking::{ExposeInterface, PeekInterface, Secret}; use pm_auth::{connector::plaid::transformers::PlaidAuthType, types as pm_auth_types}; use regex::Regex; -use router_env::metrics::add_attributes; use uuid::Uuid; #[cfg(any(feature = "v1", feature = "v2"))] @@ -2927,12 +2926,11 @@ pub async fn create_connector( .await?; metrics::MCA_CREATE.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", req.connector_name.to_string()), - ("merchant", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant", merchant_id.clone()), + ), ); let mca_response = mca.foreign_try_into()?; diff --git a/crates/router/src/core/api_keys.rs b/crates/router/src/core/api_keys.rs index de4a8931c785..4d3f3df9a59c 100644 --- a/crates/router/src/core/api_keys.rs +++ b/crates/router/src/core/api_keys.rs @@ -3,7 +3,7 @@ use common_utils::date_time; use diesel_models::{api_keys::ApiKey, enums as storage_enums}; use error_stack::{report, ResultExt}; use masking::{PeekInterface, StrongSecret}; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use crate::{ configs::settings, @@ -160,9 +160,8 @@ pub async fn create_api_key( ); metrics::API_KEY_CREATED.add( - &metrics::CONTEXT, 1, - &add_attributes([("merchant", merchant_id.get_string_repr().to_owned())]), + router_env::metric_attributes!(("merchant", merchant_id.clone())), ); // Add process to process_tracker for email reminder, only if expiry is set to future date @@ -244,11 +243,7 @@ pub async fn add_api_key_expiry_task( api_key.key_id ) })?; - metrics::TASKS_ADDED_COUNT.add( - &metrics::CONTEXT, - 1, - &add_attributes([("flow", "ApiKeyExpiry")]), - ); + metrics::TASKS_ADDED_COUNT.add(1, router_env::metric_attributes!(("flow", "ApiKeyExpiry"))); Ok(()) } @@ -456,7 +451,7 @@ pub async fn revoke_api_key( ); } - metrics::API_KEY_REVOKED.add(&metrics::CONTEXT, 1, &[]); + metrics::API_KEY_REVOKED.add(1, &[]); #[cfg(feature = "email")] { diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index 266873b1a111..3081617f3ea5 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -705,7 +705,7 @@ impl CustomerDeleteBridge for customers::GlobalId { payment_methods_deleted: true, id: self.id.clone(), }; - metrics::CUSTOMER_REDACTED.add(&metrics::CONTEXT, 1, &[]); + metrics::CUSTOMER_REDACTED.add(1, &[]); Ok(services::ApplicationResponse::Json(response)) } } @@ -943,7 +943,7 @@ impl CustomerDeleteBridge for customers::CustomerId { address_deleted: true, payment_methods_deleted: true, }; - metrics::CUSTOMER_REDACTED.add(&metrics::CONTEXT, 1, &[]); + metrics::CUSTOMER_REDACTED.add(1, &[]); Ok(services::ApplicationResponse::Json(response)) } } diff --git a/crates/router/src/core/disputes.rs b/crates/router/src/core/disputes.rs index 8f083c3103a3..15bdbafb135b 100644 --- a/crates/router/src/core/disputes.rs +++ b/crates/router/src/core/disputes.rs @@ -155,7 +155,7 @@ pub async fn accept_dispute( !(dispute.dispute_stage == storage_enums::DisputeStage::Dispute && dispute.dispute_status == storage_enums::DisputeStatus::DisputeOpened), || { - metrics::ACCEPT_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::ACCEPT_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add(1, &[]); Err(errors::ApiErrorResponse::DisputeStatusValidationFailed { reason: format!( "This dispute cannot be accepted because the dispute is in {} stage and has {} status", @@ -274,11 +274,7 @@ pub async fn submit_evidence( !(dispute.dispute_stage == storage_enums::DisputeStage::Dispute && dispute.dispute_status == storage_enums::DisputeStatus::DisputeOpened), || { - metrics::EVIDENCE_SUBMISSION_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add( - &metrics::CONTEXT, - 1, - &[], - ); + metrics::EVIDENCE_SUBMISSION_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add(1, &[]); Err(errors::ApiErrorResponse::DisputeStatusValidationFailed { reason: format!( "Evidence cannot be submitted because the dispute is in {} stage and has {} status", @@ -446,11 +442,7 @@ pub async fn attach_evidence( !(dispute.dispute_stage == storage_enums::DisputeStage::Dispute && dispute.dispute_status == storage_enums::DisputeStatus::DisputeOpened), || { - metrics::ATTACH_EVIDENCE_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add( - &metrics::CONTEXT, - 1, - &[], - ); + metrics::ATTACH_EVIDENCE_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add(1, &[]); Err(errors::ApiErrorResponse::DisputeStatusValidationFailed { reason: format!( "Evidence cannot be attached because the dispute is in {} stage and has {} status", diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs index 5ed3e9105632..da8015662a7e 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -5,7 +5,7 @@ use common_utils::{ext_traits::Encode, id_type}; use diesel_models::enums as storage_enums; use error_stack::{report, ResultExt}; use futures::future; -use router_env::{instrument, logger, metrics::add_attributes, tracing}; +use router_env::{instrument, logger, tracing}; use super::payments::helpers as payment_helper; use crate::{ @@ -341,9 +341,8 @@ where .change_context(errors::ApiErrorResponse::MandateUpdateFailed), }?; metrics::SUBSEQUENT_MANDATE_PAYMENT.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", mandate.connector)]), + router_env::metric_attributes!(("connector", mandate.connector)), ); Ok(Some(mandate_id.clone())) } @@ -396,11 +395,7 @@ where .insert_mandate(new_mandate_data, storage_scheme) .await .to_duplicate_response(errors::ApiErrorResponse::DuplicateMandate)?; - metrics::MANDATE_COUNT.add( - &metrics::CONTEXT, - 1, - &add_attributes([("connector", connector)]), - ); + metrics::MANDATE_COUNT.add(1, router_env::metric_attributes!(("connector", connector))); Ok(Some(res_mandate_id)) } } diff --git a/crates/router/src/core/metrics.rs b/crates/router/src/core/metrics.rs index 8956c38e7edd..a98a4ffb259f 100644 --- a/crates/router/src/core/metrics.rs +++ b/crates/router/src/core/metrics.rs @@ -1,7 +1,5 @@ -pub use router_env::opentelemetry::KeyValue; -use router_env::{counter_metric, global_meter, metrics_context}; +use router_env::{counter_metric, global_meter}; -metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); counter_metric!(INCOMING_DISPUTE_WEBHOOK_METRIC, GLOBAL_METER); // No. of incoming dispute webhooks diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index aaeb1aff16ac..259f77c81a30 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -54,7 +54,7 @@ use hyperswitch_domain_models::customer::CustomerUpdate; ))] use kgraph_utils::transformers::IntoDirValue; use masking::Secret; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use serde_json::json; use strum::IntoEnumIterator; @@ -2438,7 +2438,7 @@ pub async fn add_card_to_locker( ), errors::VaultError, > { - metrics::STORED_TO_LOCKER.add(&metrics::CONTEXT, 1, &[]); + metrics::STORED_TO_LOCKER.add(1, &[]); let add_card_to_hs_resp = Box::pin(common_utils::metrics::utils::record_operation_time( async { add_card_hs( @@ -2453,18 +2453,13 @@ pub async fn add_card_to_locker( .await .inspect_err(|_| { metrics::CARD_LOCKER_FAILURES.add( - &metrics::CONTEXT, 1, - &[ - router_env::opentelemetry::KeyValue::new("locker", "rust"), - router_env::opentelemetry::KeyValue::new("operation", "add"), - ], + router_env::metric_attributes!(("locker", "rust"), ("operation", "add")), ); }) }, &metrics::CARD_ADD_TIME, - &metrics::CONTEXT, - &[router_env::opentelemetry::KeyValue::new("locker", "rust")], + router_env::metric_attributes!(("locker", "rust")), )) .await?; @@ -2478,7 +2473,7 @@ pub async fn get_card_from_locker( merchant_id: &id_type::MerchantId, card_reference: &str, ) -> errors::RouterResult { - metrics::GET_FROM_LOCKER.add(&metrics::CONTEXT, 1, &[]); + metrics::GET_FROM_LOCKER.add(1, &[]); let get_card_from_rs_locker_resp = common_utils::metrics::utils::record_operation_time( async { @@ -2494,18 +2489,13 @@ pub async fn get_card_from_locker( .attach_printable("Failed while getting card from hyperswitch card vault") .inspect_err(|_| { metrics::CARD_LOCKER_FAILURES.add( - &metrics::CONTEXT, 1, - &[ - router_env::opentelemetry::KeyValue::new("locker", "rust"), - router_env::opentelemetry::KeyValue::new("operation", "get"), - ], + router_env::metric_attributes!(("locker", "rust"), ("operation", "get")), ); }) }, &metrics::CARD_GET_TIME, - &metrics::CONTEXT, - &[router_env::opentelemetry::KeyValue::new("locker", "rust")], + router_env::metric_attributes!(("locker", "rust")), ) .await?; @@ -2519,7 +2509,7 @@ pub async fn delete_card_from_locker( merchant_id: &id_type::MerchantId, card_reference: &str, ) -> errors::RouterResult { - metrics::DELETE_FROM_LOCKER.add(&metrics::CONTEXT, 1, &[]); + metrics::DELETE_FROM_LOCKER.add(1, &[]); common_utils::metrics::utils::record_operation_time( async move { @@ -2527,17 +2517,12 @@ pub async fn delete_card_from_locker( .await .inspect_err(|_| { metrics::CARD_LOCKER_FAILURES.add( - &metrics::CONTEXT, 1, - &[ - router_env::opentelemetry::KeyValue::new("locker", "rust"), - router_env::opentelemetry::KeyValue::new("operation", "delete"), - ], + router_env::metric_attributes!(("locker", "rust"), ("operation", "delete")), ); }) }, &metrics::CARD_DELETE_TIME, - &metrics::CONTEXT, &[], ) .await @@ -5778,11 +5763,10 @@ impl TempLockerCardSupport { enums::PaymentMethod::Card, ) .await?; - metrics::TOKENIZED_DATA_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::TOKENIZED_DATA_COUNT.add(1, &[]); metrics::TASKS_ADDED_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("flow", "DeleteTokenizeData")]), + router_env::metric_attributes!(("flow", "DeleteTokenizeData")), ); Ok(card) } diff --git a/crates/router/src/core/payment_methods/network_tokenization.rs b/crates/router/src/core/payment_methods/network_tokenization.rs index f02bfaa42617..de4524104788 100644 --- a/crates/router/src/core/payment_methods/network_tokenization.rs +++ b/crates/router/src/core/payment_methods/network_tokenization.rs @@ -296,8 +296,7 @@ pub async fn make_card_network_tokenization_request( ) }, &metrics::GENERATE_NETWORK_TOKEN_TIME, - &metrics::CONTEXT, - &[router_env::opentelemetry::KeyValue::new("locker", "rust")], + router_env::metric_attributes!(("locker", "rust")), ) .await } else { @@ -399,7 +398,6 @@ pub async fn get_token_from_tokenization_service( .attach_printable("Fetch network token failed") }, &metrics::FETCH_NETWORK_TOKEN_TIME, - &metrics::CONTEXT, &[], ) .await @@ -483,7 +481,7 @@ pub async fn do_status_check_for_network_token( ) }, &metrics::CHECK_NETWORK_TOKEN_STATUS_TIME, - &metrics::CONTEXT, + &[], ) .await?; @@ -608,7 +606,6 @@ pub async fn delete_network_token_from_locker_and_token_service( .await }, &metrics::DELETE_NETWORK_TOKEN_TIME, - &metrics::CONTEXT, &[], ) .await; diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs index e4f72c717f6c..32a42d301659 100644 --- a/crates/router/src/core/payment_methods/vault.rs +++ b/crates/router/src/core/payment_methods/vault.rs @@ -9,7 +9,7 @@ use common_utils::{ }; use error_stack::{report, ResultExt}; use masking::PeekInterface; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use scheduler::{types::process_data, utils as process_tracker_utils}; #[cfg(feature = "payouts")] @@ -927,7 +927,7 @@ impl Vault { ) .await?; add_delete_tokenized_data_task(&*state.store, &lookup_key, pm).await?; - metrics::TOKENIZED_DATA_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::TOKENIZED_DATA_COUNT.add(1, &[]); Ok(lookup_key) } @@ -979,7 +979,7 @@ impl Vault { ) .await?; // add_delete_tokenized_data_task(&*state.store, &lookup_key, pm).await?; - // scheduler_metrics::TOKENIZED_DATA_COUNT.add(&metrics::CONTEXT, 1, &[]); + // scheduler_metrics::TOKENIZED_DATA_COUNT.add(1, &[]); Ok(lookup_key) } @@ -1015,7 +1015,7 @@ pub async fn create_tokenize( ) -> RouterResult { let redis_key = get_redis_locker_key(lookup_key.as_str()); let func = || async { - metrics::CREATED_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); + metrics::CREATED_TOKENIZED_CARD.add(1, &[]); let payload_to_be_encrypted = api::TokenizePayloadRequest { value1: value1.clone(), @@ -1048,7 +1048,7 @@ pub async fn create_tokenize( .await .map(|_| lookup_key.clone()) .inspect_err(|error| { - metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::TEMP_LOCKER_FAILURES.add(1, &[]); logger::error!(?error, "Failed to store tokenized data in Redis"); }) .change_context(errors::ApiErrorResponse::InternalServerError) @@ -1079,7 +1079,7 @@ pub async fn get_tokenized_data( ) -> RouterResult { let redis_key = get_redis_locker_key(lookup_key); let func = || async { - metrics::GET_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); + metrics::GET_TOKENIZED_CARD.add(1, &[]); let redis_conn = state .store @@ -1110,7 +1110,7 @@ pub async fn get_tokenized_data( Ok(get_response) } Err(err) => { - metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::TEMP_LOCKER_FAILURES.add(1, &[]); Err(err).change_context(errors::ApiErrorResponse::UnprocessableEntity { message: "Token is invalid or expired".into(), }) @@ -1140,7 +1140,7 @@ pub async fn delete_tokenized_data( ) -> RouterResult<()> { let redis_key = get_redis_locker_key(lookup_key); let func = || async { - metrics::DELETED_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); + metrics::DELETED_TOKENIZED_CARD.add(1, &[]); let redis_conn = state .store @@ -1157,7 +1157,7 @@ pub async fn delete_tokenized_data( .attach_printable("Token invalid or expired") } Err(err) => { - metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::TEMP_LOCKER_FAILURES.add(1, &[]); Err(errors::ApiErrorResponse::InternalServerError).attach_printable_lazy(|| { format!("Failed to delete from redis locker: {err:?}") }) @@ -1435,7 +1435,7 @@ pub async fn start_tokenize_data_workflow( Err(err) => { logger::error!("Err: Deleting Card From Locker : {:?}", err); retry_delete_tokenize(db, delete_tokenize_data.pm, tokenize_tracker.to_owned()).await?; - metrics::RETRIED_DELETE_DATA_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::RETRIED_DELETE_DATA_COUNT.add(1, &[]); } } Ok(()) @@ -1479,9 +1479,8 @@ pub async fn retry_delete_tokenize( .await .map_err(Into::into); metrics::TASKS_RESET_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("flow", "DeleteTokenizeData")]), + router_env::metric_attributes!(("flow", "DeleteTokenizeData")), ); retry_schedule } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index dea0ca351231..dcbafa5aa9d3 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -54,7 +54,7 @@ use masking::{ExposeInterface, PeekInterface, Secret}; #[cfg(feature = "v2")] use operations::ValidateStatusForOperation; use redis_interface::errors::RedisError; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; #[cfg(feature = "olap")] use router_types::transformers::ForeignFrom; use scheduler::utils as pt_utils; @@ -1650,18 +1650,14 @@ pub trait PaymentRedirectFlow: Sync { req: PaymentsRedirectResponseData, ) -> RouterResponse { metrics::REDIRECTION_TRIGGERED.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", req.connector.to_owned().unwrap_or("null".to_string()), ), - ( - "merchant_id", - merchant_account.get_id().get_string_repr().to_owned(), - ), - ]), + ("merchant_id", merchant_account.get_id().clone()), + ), ); let connector = req.connector.clone().get_required_value("connector")?; @@ -1723,12 +1719,8 @@ pub trait PaymentRedirectFlow: Sync { request: PaymentsRedirectResponseData, ) -> RouterResponse { metrics::REDIRECTION_TRIGGERED.add( - &metrics::CONTEXT, 1, - &add_attributes([( - "merchant_id", - merchant_account.get_id().get_string_repr().to_owned(), - )]), + router_env::metric_attributes!(("merchant_id", merchant_account.get_id().clone())), ); let payment_flow_response = self @@ -4576,11 +4568,7 @@ pub async fn apply_filters_on_payments( )) }, &metrics::PAYMENT_LIST_LATENCY, - &metrics::CONTEXT, - &[router_env::opentelemetry::KeyValue::new( - "merchant_id", - merchant.get_id().clone(), - )], + router_env::metric_attributes!(("merchant_id", merchant.get_id().clone())), ) .await } diff --git a/crates/router/src/core/payments/access_token.rs b/crates/router/src/core/payments/access_token.rs index 42d0823a256c..7d56c2ccb910 100644 --- a/crates/router/src/core/payments/access_token.rs +++ b/crates/router/src/core/payments/access_token.rs @@ -2,7 +2,6 @@ use std::fmt::Debug; use common_utils::ext_traits::AsyncExt; use error_stack::ResultExt; -use router_env::metrics::add_attributes; use crate::{ consts, @@ -96,17 +95,21 @@ pub async fn add_access_token< access_token.expires ); metrics::ACCESS_TOKEN_CACHE_HIT.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(( + "connector", + connector.connector_name.to_string() + )), ); Ok(Some(access_token)) } None => { metrics::ACCESS_TOKEN_CACHE_MISS.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(( + "connector", + connector.connector_name.to_string() + )), ); let cloned_router_data = router_data.clone(); @@ -242,9 +245,8 @@ pub async fn refresh_connector_auth( }?; metrics::ACCESS_TOKEN_CREATION.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(("connector", connector.connector_name.to_string())), ); Ok(access_token_router_data) } diff --git a/crates/router/src/core/payments/customers.rs b/crates/router/src/core/payments/customers.rs index 4b71c43aca66..b11216c423dd 100644 --- a/crates/router/src/core/payments/customers.rs +++ b/crates/router/src/core/payments/customers.rs @@ -1,6 +1,6 @@ use common_utils::pii; use masking::{ExposeOptionInterface, PeekInterface}; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use crate::{ core::{ @@ -53,9 +53,8 @@ pub async fn create_connector_customer( .to_payment_failed_response()?; metrics::CONNECTOR_CUSTOMER_CREATE.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(("connector", connector.connector_name.to_string())), ); let connector_customer_id = match resp.response { diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 7ee407fa9e02..75eda0ed9138 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -4,7 +4,6 @@ use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse; #[cfg(feature = "v2")] use hyperswitch_domain_models::payments::PaymentConfirmData; use masking::ExposeInterface; -use router_env::metrics::add_attributes; // use router_env::tracing::Instrument; use super::{ConstructFlowSpecificData, Feature}; @@ -205,7 +204,7 @@ impl Feature for types::PaymentsAu &auth_router_data.response, ); auth_router_data.integrity_check = integrity_result; - metrics::PAYMENT_COUNT.add(&metrics::CONTEXT, 1, &[]); // Move outside of the if block + metrics::PAYMENT_COUNT.add(1, &[]); // Move outside of the if block match auth_router_data.response.clone() { Err(_) => Ok(auth_router_data), @@ -363,12 +362,11 @@ impl Feature for types::PaymentsAu > = connector.connector.get_connector_integration(); metrics::EXECUTE_PRETASK_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", connector.connector_name.to_string()), ("flow", format!("{:?}", api::Authorize)), - ]), + ), ); logger::debug!(completed_pre_tasks=?true); @@ -497,9 +495,8 @@ pub async fn authorize_preprocessing_steps( .to_payment_failed_response()?; metrics::PREPROCESSING_STEPS_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", connector.connector_name.to_string()), ("payment_method", router_data.payment_method.to_string()), ( @@ -507,11 +504,10 @@ pub async fn authorize_preprocessing_steps( router_data .request .payment_method_type - .as_ref() .map(|inner| inner.to_string()) .unwrap_or("null".to_string()), ), - ]), + ), ); let mut authorize_router_data = helpers::router_data_type_conversion::<_, F, _, _, _, _>( resp.clone(), diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index e9c3f63c7920..4d2d6294197f 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -1,5 +1,4 @@ use async_trait::async_trait; -use router_env::metrics::add_attributes; use super::{ConstructFlowSpecificData, Feature}; use crate::{ @@ -86,9 +85,8 @@ impl Feature _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { metrics::PAYMENT_CANCEL_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(("connector", connector.connector_name.to_string())), ); let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs index e347cd3c3d52..44bb9f2703af 100644 --- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs +++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs @@ -1,6 +1,5 @@ use async_trait::async_trait; use masking::ExposeInterface; -use router_env::metrics::add_attributes; use super::{ConstructFlowSpecificData, Feature}; use crate::{ @@ -256,12 +255,11 @@ pub async fn complete_authorize_preprocessing_steps( .to_payment_failed_response()?; metrics::PREPROCESSING_STEPS_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", connector.connector_name.to_string()), ("payment_method", router_data.payment_method.to_string()), - ]), + ), ); let mut router_data_request = router_data.request.to_owned(); diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 71049a56241d..464781f3d7cc 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -9,7 +9,6 @@ use error_stack::{Report, ResultExt}; #[cfg(feature = "v2")] use hyperswitch_domain_models::payments::PaymentIntentData; use masking::ExposeInterface; -use router_env::metrics::add_attributes; use super::{ConstructFlowSpecificData, Feature}; use crate::{ @@ -129,9 +128,8 @@ impl Feature for types::PaymentsSessio header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { metrics::SESSION_TOKEN_CREATED.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(("connector", connector.connector_name.to_string())), ); self.decide_flow( state, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 6d40593060dd..01bac9a21242 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -42,7 +42,7 @@ use openssl::{ pkey::PKey, symm::{decrypt_aead, Cipher}, }; -use router_env::{instrument, logger, metrics::add_attributes, tracing}; +use router_env::{instrument, logger, tracing}; use uuid::Uuid; use x509_parser::parse_x509_certificate; @@ -1398,9 +1398,8 @@ where if !requeue { // Here, increment the count of added tasks every time a payment has been confirmed or PSync has been called metrics::TASKS_ADDED_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("flow", format!("{:#?}", operation))]), + router_env::metric_attributes!(("flow", format!("{:#?}", operation))), ); super::add_process_sync_task(&*state.store, payment_attempt, stime) .await @@ -1409,9 +1408,8 @@ where } else { // When the requeue is true, we reset the tasks count as we reset the task every time it is requeued metrics::TASKS_RESET_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("flow", format!("{:#?}", operation))]), + router_env::metric_attributes!(("flow", format!("{:#?}", operation))), ); super::reset_process_sync_task(&*state.store, payment_attempt, stime) .await @@ -1723,7 +1721,7 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>( updated_by: None, version: hyperswitch_domain_models::consts::API_VERSION, }; - metrics::CUSTOMER_CREATED.add(&metrics::CONTEXT, 1, &[]); + metrics::CUSTOMER_CREATED.add(1, &[]); db.insert_customer(new_customer, key_manager_state, key_store, storage_scheme) .await } @@ -3959,12 +3957,11 @@ pub fn get_attempt_type( Some(api_models::enums::RetryAction::ManualRetry) ) { metrics::MANUAL_RETRY_REQUEST_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([( + router_env::metric_attributes!(( "merchant_id", - payment_attempt.merchant_id.get_string_repr().to_owned(), - )]), + payment_attempt.merchant_id.clone(), + )), ); match payment_attempt.status { enums::AttemptStatus::Started @@ -3986,12 +3983,11 @@ pub fn get_attempt_type( | enums::AttemptStatus::PaymentMethodAwaited | enums::AttemptStatus::DeviceDataCollectionPending => { metrics::MANUAL_RETRY_VALIDATION_FAILED.add( - &metrics::CONTEXT, 1, - &add_attributes([( + router_env::metric_attributes!(( "merchant_id", - payment_attempt.merchant_id.get_string_repr().to_owned(), - )]), + payment_attempt.merchant_id.clone(), + )), ); Err(errors::ApiErrorResponse::InternalServerError) .attach_printable("Payment Attempt unexpected state") @@ -4001,12 +3997,11 @@ pub fn get_attempt_type( | storage_enums::AttemptStatus::RouterDeclined | storage_enums::AttemptStatus::CaptureFailed => { metrics::MANUAL_RETRY_VALIDATION_FAILED.add( - &metrics::CONTEXT, 1, - &add_attributes([( + router_env::metric_attributes!(( "merchant_id", - payment_attempt.merchant_id.get_string_repr().to_owned(), - )]), + payment_attempt.merchant_id.clone(), + )), ); Err(report!(errors::ApiErrorResponse::PreconditionFailed { message: @@ -4019,12 +4014,11 @@ pub fn get_attempt_type( | storage_enums::AttemptStatus::AuthorizationFailed | storage_enums::AttemptStatus::Failure => { metrics::MANUAL_RETRY_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([( + router_env::metric_attributes!(( "merchant_id", - payment_attempt.merchant_id.get_string_repr().to_owned(), - )]), + payment_attempt.merchant_id.clone(), + )), ); Ok(AttemptType::New) } @@ -5465,9 +5459,9 @@ pub async fn get_gsm_record( error_code, error_message ); - metrics::AUTO_RETRY_GSM_MISS_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_GSM_MISS_COUNT.add( 1, &[]); } else { - metrics::AUTO_RETRY_GSM_FETCH_FAILURE_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_GSM_FETCH_FAILURE_COUNT.add( 1, &[]); }; err.change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed to fetch decision from gsm") diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index d77236c8a2bc..01a4e0860918 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -17,7 +17,7 @@ use hyperswitch_domain_models::payments::{ PaymentConfirmData, PaymentIntentData, PaymentStatusData, }; use router_derive; -use router_env::{instrument, logger, metrics::add_attributes, tracing}; +use router_env::{instrument, logger, tracing}; use storage_impl::DataModelExt; use tracing_futures::Instrument; @@ -1655,7 +1655,7 @@ async fn payment_response_update_tracker( } } - metrics::SUCCESSFUL_PAYMENT.add(&metrics::CONTEXT, 1, &[]); + metrics::SUCCESSFUL_PAYMENT.add(1, &[]); } let payment_method_id = @@ -2034,9 +2034,8 @@ async fn payment_response_update_tracker( Ok(()) => Ok(payment_data), Err(err) => { metrics::INTEGRITY_CHECK_FAILED.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", payment_data @@ -2047,13 +2046,9 @@ async fn payment_response_update_tracker( ), ( "merchant_id", - payment_data - .payment_attempt - .merchant_id - .get_string_repr() - .to_owned(), - ), - ]), + payment_data.payment_attempt.merchant_id.clone(), + ) + ), ); Err(error_stack::Report::new( errors::ApiErrorResponse::IntegrityCheckFailed { diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index fed28b680110..7ae536a1f193 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -61,7 +61,7 @@ where { let mut retries = None; - metrics::AUTO_RETRY_ELIGIBLE_REQUEST_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_ELIGIBLE_REQUEST_COUNT.add(1, &[]); let mut initial_gsm = get_gsm(state, &router_data).await?; @@ -129,14 +129,14 @@ where .await; if retries.is_none() || retries == Some(0) { - metrics::AUTO_RETRY_EXHAUSTED_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_EXHAUSTED_COUNT.add(1, &[]); logger::info!("retries exhausted for auto_retry payment"); break; } if connectors.len() == 0 { logger::info!("connectors exhausted for auto_retry payment"); - metrics::AUTO_RETRY_EXHAUSTED_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_EXHAUSTED_COUNT.add(1, &[]); break; } @@ -275,7 +275,7 @@ pub fn get_gsm_decision( }); if option_gsm_decision.is_some() { - metrics::AUTO_RETRY_GSM_MATCH_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_GSM_MATCH_COUNT.add(1, &[]); } option_gsm_decision.unwrap_or_default() } @@ -323,7 +323,7 @@ where types::RouterData: Feature, dyn api::Connector: services::api::ConnectorIntegration, { - metrics::AUTO_RETRY_PAYMENT_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_PAYMENT_COUNT.add(1, &[]); modify_trackers( state, diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index efee99bb7a0e..89fb7752d1b0 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -16,7 +16,7 @@ use common_utils::{ }; use error_stack::{report, ResultExt}; use masking::{ExposeInterface, Secret}; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use super::helpers; use crate::{ @@ -1090,12 +1090,11 @@ pub async fn add_payment_method_token( .to_payment_failed_response()?; metrics::CONNECTOR_PAYMENT_METHOD_TOKENIZATION.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", connector.connector_name.to_string()), ("payment_method", router_data.payment_method.to_string()), - ]), + ), ); let payment_token_resp = resp.response.map(|res| { diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 6e277ed460f0..0f248d6cc36c 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -21,7 +21,7 @@ use hyperswitch_domain_models::payments::{PaymentConfirmData, PaymentIntentData} use hyperswitch_domain_models::ApiModelToDieselModelConvertor; use hyperswitch_domain_models::{payments::payment_intent::CustomerData, router_request_types}; use masking::{ExposeInterface, Maskable, PeekInterface, Secret}; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use super::{flows::Feature, types::AuthenticationData, OperationSessionGetters, PaymentData}; use crate::{ @@ -2084,14 +2084,13 @@ where }; metrics::PAYMENT_OPS_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("operation", format!("{:?}", operation)), - ("merchant", merchant_id.get_string_repr().to_owned()), + ("merchant", merchant_id.clone()), ("payment_method_type", payment_method_type), ("payment_method", payment_method), - ]), + ), ); Ok(output) diff --git a/crates/router/src/core/payouts/access_token.rs b/crates/router/src/core/payouts/access_token.rs index b7f52b259c04..e5e9b47e4ffa 100644 --- a/crates/router/src/core/payouts/access_token.rs +++ b/crates/router/src/core/payouts/access_token.rs @@ -1,6 +1,5 @@ use common_utils::ext_traits::AsyncExt; use error_stack::ResultExt; -use router_env::metrics::add_attributes; use crate::{ consts, @@ -185,9 +184,8 @@ pub async fn refresh_connector_auth( }?; metrics::ACCESS_TOKEN_CREATION.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(("connector", connector.connector_name.to_string())), ); Ok(access_token_router_data) } diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 5becf01597cb..de287defa868 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -981,9 +981,9 @@ pub async fn get_gsm_record( error_code, error_message ); - metrics::AUTO_PAYOUT_RETRY_GSM_MISS_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_GSM_MISS_COUNT.add( 1, &[]); } else { - metrics::AUTO_PAYOUT_RETRY_GSM_FETCH_FAILURE_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_GSM_FETCH_FAILURE_COUNT.add( 1, &[]); }; err.change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed to fetch decision from gsm") diff --git a/crates/router/src/core/payouts/retry.rs b/crates/router/src/core/payouts/retry.rs index ed7e4a9b4b88..662bdb334a80 100644 --- a/crates/router/src/core/payouts/retry.rs +++ b/crates/router/src/core/payouts/retry.rs @@ -31,7 +31,7 @@ pub async fn do_gsm_multiple_connector_actions( ) -> RouterResult<()> { let mut retries = None; - metrics::AUTO_PAYOUT_RETRY_ELIGIBLE_REQUEST_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_ELIGIBLE_REQUEST_COUNT.add(1, &[]); let mut connector = original_connector_data; @@ -49,14 +49,14 @@ pub async fn do_gsm_multiple_connector_actions( .await; if retries.is_none() || retries == Some(0) { - metrics::AUTO_PAYOUT_RETRY_EXHAUSTED_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_EXHAUSTED_COUNT.add(1, &[]); logger::info!("retries exhausted for auto_retry payout"); break; } if connectors.len() == 0 { logger::info!("connectors exhausted for auto_retry payout"); - metrics::AUTO_PAYOUT_RETRY_EXHAUSTED_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_EXHAUSTED_COUNT.add(1, &[]); break; } @@ -97,7 +97,7 @@ pub async fn do_gsm_single_connector_actions( ) -> RouterResult<()> { let mut retries = None; - metrics::AUTO_PAYOUT_RETRY_ELIGIBLE_REQUEST_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_ELIGIBLE_REQUEST_COUNT.add(1, &[]); let mut previous_gsm = None; // to compare previous status @@ -121,7 +121,7 @@ pub async fn do_gsm_single_connector_actions( .await; if retries.is_none() || retries == Some(0) { - metrics::AUTO_PAYOUT_RETRY_EXHAUSTED_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_EXHAUSTED_COUNT.add(1, &[]); logger::info!("retries exhausted for auto_retry payment"); break; } @@ -218,7 +218,7 @@ pub fn get_gsm_decision( }); if option_gsm_decision.is_some() { - metrics::AUTO_PAYOUT_RETRY_GSM_MATCH_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_PAYOUT_RETRY_GSM_MATCH_COUNT.add(1, &[]); } option_gsm_decision.unwrap_or_default() } @@ -232,7 +232,7 @@ pub async fn do_retry( key_store: &domain::MerchantKeyStore, payout_data: &mut PayoutData, ) -> RouterResult<()> { - metrics::AUTO_RETRY_PAYOUT_COUNT.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_PAYOUT_COUNT.add(1, &[]); modify_trackers(state, &connector, merchant_account, payout_data).await?; diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index ebc4c926599a..b13fb930cd74 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -15,7 +15,7 @@ use error_stack::{report, ResultExt}; use hyperswitch_domain_models::router_data::ErrorResponse; use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject}; use masking::PeekInterface; -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use scheduler::{consumer::types::process_data, utils as process_tracker_utils}; #[cfg(feature = "olap")] use strum::IntoEnumIterator; @@ -153,9 +153,8 @@ pub async fn trigger_refund_to_gateway( let storage_scheme = merchant_account.storage_scheme; metrics::REFUND_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", routed_through.clone())]), + router_env::metric_attributes!(("connector", routed_through.clone())), ); let connector: api::ConnectorData = api::ConnectorData::get_connector_by_name( @@ -302,15 +301,11 @@ pub async fn trigger_refund_to_gateway( (Some(refund_id), refund_data) }); metrics::INTEGRITY_CHECK_FAILED.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", connector.connector_name.to_string()), - ( - "merchant_id", - merchant_account.get_id().get_string_repr().to_owned(), - ), - ]), + ("merchant_id", merchant_account.get_id().clone()), + ), ); storage::RefundUpdate::ErrorUpdate { refund_status: Some(enums::RefundStatus::ManualReview), @@ -327,9 +322,11 @@ pub async fn trigger_refund_to_gateway( Ok(()) => { if response.refund_status == diesel_models::enums::RefundStatus::Success { metrics::SUCCESSFUL_REFUND.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", connector.connector_name.to_string())]), + router_env::metric_attributes!(( + "connector", + connector.connector_name.to_string(), + )), ) } let (connector_refund_id, connector_refund_data) = @@ -619,15 +616,11 @@ pub async fn sync_refund_with_gateway( Ok(response) => match router_data_res.integrity_check.clone() { Err(err) => { metrics::INTEGRITY_CHECK_FAILED.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", connector.connector_name.to_string()), - ( - "merchant_id", - merchant_account.get_id().get_string_repr().to_owned(), - ), - ]), + ("merchant_id", merchant_account.get_id().clone()), + ), ); let (refund_connector_transaction_id, connector_refund_data) = err .connector_transaction_id @@ -1590,7 +1583,7 @@ pub async fn add_refund_sync_task( refund.refund_id ) })?; - metrics::TASKS_ADDED_COUNT.add(&metrics::CONTEXT, 1, &add_attributes([("flow", "Refund")])); + metrics::TASKS_ADDED_COUNT.add(1, router_env::metric_attributes!(("flow", "Refund"))); Ok(response) } diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index cdd8b518f35a..cf04bec75a00 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -16,8 +16,6 @@ use external_services::grpc_client::dynamic_routing::SuccessBasedDynamicRouting; use hyperswitch_domain_models::{mandates, payment_address}; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] use router_env::logger; -#[cfg(feature = "v1")] -use router_env::metrics::add_attributes; use rustc_hash::FxHashSet; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] use storage_impl::redis::cache; @@ -137,7 +135,7 @@ pub async fn retrieve_merchant_routing_dictionary( query_params: RoutingRetrieveQuery, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE.add(1, &[]); let routing_metadata: Vec = state .store @@ -157,7 +155,7 @@ pub async fn retrieve_merchant_routing_dictionary( .map(ForeignInto::foreign_into) .collect::>(); - metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( routing_types::RoutingKind::RoutingAlgorithm(result), )) @@ -172,7 +170,7 @@ pub async fn create_routing_algorithm_under_profile( request: routing_types::RoutingConfigRequest, transaction_type: enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(1, &[]); let db = &*state.store; let key_manager_state = &(&state).into(); @@ -229,7 +227,7 @@ pub async fn create_routing_algorithm_under_profile( let new_record = record.foreign_into(); - metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(new_record)) } @@ -242,7 +240,7 @@ pub async fn create_routing_algorithm_under_profile( request: routing_types::RoutingConfigRequest, transaction_type: enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -319,7 +317,7 @@ pub async fn create_routing_algorithm_under_profile( let new_record = record.foreign_into(); - metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(new_record)) } @@ -332,7 +330,7 @@ pub async fn link_routing_config_under_profile( algorithm_id: common_utils::id_type::RoutingId, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_LINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_LINK_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -387,7 +385,7 @@ pub async fn link_routing_config_under_profile( ) .await?; - metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( routing_algorithm.0.foreign_into(), )) @@ -402,7 +400,7 @@ pub async fn link_routing_config( algorithm_id: common_utils::id_type::RoutingId, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_LINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_LINK_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -539,7 +537,7 @@ pub async fn link_routing_config( } }; - metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( routing_algorithm.foreign_into(), )) @@ -553,7 +551,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( authentication_profile_id: Option, algorithm_id: common_utils::id_type::RoutingId, ) -> RouterResponse { - metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -577,7 +575,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to parse routing algorithm")?; - metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(response)) } @@ -589,7 +587,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( authentication_profile_id: Option, algorithm_id: common_utils::id_type::RoutingId, ) -> RouterResponse { - metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -618,7 +616,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to parse routing algorithm")?; - metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(response)) } @@ -630,7 +628,7 @@ pub async fn unlink_routing_config_under_profile( profile_id: common_utils::id_type::ProfileId, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_UNLINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UNLINK_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -667,7 +665,7 @@ pub async fn unlink_routing_config_under_profile( transaction_type, ) .await?; - metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(response)) } else { Err(errors::ApiErrorResponse::PreconditionFailed { @@ -685,7 +683,7 @@ pub async fn unlink_routing_config( authentication_profile_id: Option, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_UNLINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UNLINK_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -754,7 +752,7 @@ pub async fn unlink_routing_config( ) .await?; - metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(response)) } None => Err(errors::ApiErrorResponse::PreconditionFailed { @@ -777,7 +775,7 @@ pub async fn update_default_fallback_routing( profile_id: common_utils::id_type::ProfileId, updated_list_of_connectors: Vec, ) -> RouterResponse> { - metrics::ROUTING_UPDATE_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UPDATE_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); let profile = core_utils::validate_and_get_business_profile( @@ -839,7 +837,7 @@ pub async fn update_default_fallback_routing( ) .await?; - metrics::ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( updated_list_of_connectors, )) @@ -852,7 +850,7 @@ pub async fn update_default_routing_config( updated_config: Vec, transaction_type: &enums::TransactionType, ) -> RouterResponse> { - metrics::ROUTING_UPDATE_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UPDATE_CONFIG.add(1, &[]); let db = state.store.as_ref(); let default_config = helpers::get_merchant_default_config( db, @@ -894,7 +892,7 @@ pub async fn update_default_routing_config( ) .await?; - metrics::ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(updated_config)) } @@ -905,7 +903,7 @@ pub async fn retrieve_default_fallback_algorithm_for_profile( key_store: domain::MerchantKeyStore, profile_id: common_utils::id_type::ProfileId, ) -> RouterResponse> { - metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); let profile = core_utils::validate_and_get_business_profile( @@ -921,7 +919,7 @@ pub async fn retrieve_default_fallback_algorithm_for_profile( let connectors_choice = admin::ProfileWrapper::new(profile) .get_default_fallback_list_of_connector_under_profile()?; - metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(connectors_choice)) } @@ -932,7 +930,7 @@ pub async fn retrieve_default_routing_config( merchant_account: domain::MerchantAccount, transaction_type: &enums::TransactionType, ) -> RouterResponse> { - metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG.add(1, &[]); let db = state.store.as_ref(); let id = profile_id .map(|profile_id| profile_id.get_string_repr().to_owned()) @@ -941,11 +939,7 @@ pub async fn retrieve_default_routing_config( helpers::get_merchant_default_config(db, &id, transaction_type) .await .map(|conn_choice| { - metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, - 1, - &[], - ); + metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE.add(1, &[]); service_api::ApplicationResponse::Json(conn_choice) }) } @@ -959,7 +953,7 @@ pub async fn retrieve_routing_config_under_profile( profile_id: common_utils::id_type::ProfileId, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -988,7 +982,7 @@ pub async fn retrieve_routing_config_under_profile( .map(|routing_algo| routing_algo.foreign_into()) .collect::>(); - metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( routing_types::LinkedRoutingConfigRetrieveResponse::ProfileBased(active_algorithms), )) @@ -1003,7 +997,7 @@ pub async fn retrieve_linked_routing_config( query_params: routing_types::RoutingRetrieveLinkQuery, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -1062,7 +1056,7 @@ pub async fn retrieve_linked_routing_config( } } - metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( routing_types::LinkedRoutingConfigRetrieveResponse::ProfileBased(active_algorithms), )) @@ -1074,7 +1068,7 @@ pub async fn retrieve_default_routing_config_for_profiles( key_store: domain::MerchantKeyStore, transaction_type: &enums::TransactionType, ) -> RouterResponse> { - metrics::ROUTING_RETRIEVE_CONFIG_FOR_PROFILE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_CONFIG_FOR_PROFILE.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -1111,7 +1105,7 @@ pub async fn retrieve_default_routing_config_for_profiles( ) .collect::>(); - metrics::ROUTING_RETRIEVE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_RETRIEVE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json(default_configs)) } @@ -1123,7 +1117,7 @@ pub async fn update_default_routing_config_for_profile( profile_id: common_utils::id_type::ProfileId, transaction_type: &enums::TransactionType, ) -> RouterResponse { - metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(1, &[]); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -1190,7 +1184,7 @@ pub async fn update_default_routing_config_for_profile( ) .await?; - metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]); + metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(1, &[]); Ok(service_api::ApplicationResponse::Json( routing_types::ProfileDefaultRoutingConfig { profile_id: business_profile.get_id().to_owned(), @@ -1211,9 +1205,8 @@ pub async fn toggle_specific_dynamic_routing( dynamic_routing_type: routing::DynamicRoutingType, ) -> RouterResponse { metrics::ROUTING_CREATE_REQUEST_RECEIVED.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), + router_env::metric_attributes!(("profile_id", profile_id.clone())), ); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -1282,9 +1275,8 @@ pub async fn configure_dynamic_routing_volume_split( routing_info: routing::RoutingVolumeSplit, ) -> RouterResponse<()> { metrics::ROUTING_CREATE_REQUEST_RECEIVED.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), + router_env::metric_attributes!(("profile_id", profile_id.clone())), ); let db = state.store.as_ref(); let key_manager_state = &(&state).into(); @@ -1344,9 +1336,8 @@ pub async fn success_based_routing_update_configs( profile_id: common_utils::id_type::ProfileId, ) -> RouterResponse { metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), + router_env::metric_attributes!(("profile_id", profile_id.clone())), ); let db = state.store.as_ref(); @@ -1402,9 +1393,8 @@ pub async fn success_based_routing_update_configs( let new_record = record.foreign_into(); metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), + router_env::metric_attributes!(("profile_id", profile_id.clone())), ); let prefix_of_dynamic_routing_keys = helpers::generate_tenant_business_profile_id( diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 112c014202e6..690293c7f6ba 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -24,7 +24,7 @@ use hyperswitch_domain_models::api::ApplicationResponse; #[cfg(all(feature = "dynamic_routing", feature = "v1"))] use router_env::logger; #[cfg(any(feature = "dynamic_routing", feature = "v1"))] -use router_env::{instrument, metrics::add_attributes, tracing}; +use router_env::{instrument, tracing}; use rustc_hash::FxHashSet; use storage_impl::redis::cache; @@ -40,7 +40,7 @@ use crate::{ utils::StringExt, }; #[cfg(feature = "v1")] -use crate::{core::metrics as core_metrics, routes::metrics, types::transformers::ForeignInto}; +use crate::{core::metrics as core_metrics, types::transformers::ForeignInto}; pub const SUCCESS_BASED_DYNAMIC_ROUTING_ALGORITHM: &str = "Success rate based dynamic routing algorithm"; pub const ELIMINATION_BASED_DYNAMIC_ROUTING_ALGORITHM: &str = @@ -771,9 +771,8 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( }; core_metrics::DYNAMIC_SUCCESS_BASED_ROUTING.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "tenant", state.tenant.tenant_id.get_string_repr().to_owned(), @@ -827,7 +826,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ), ("payment_status", payment_attempt.status.to_string()), ("conclusive_classification", outcome.to_string()), - ]), + ), ); logger::debug!("successfully pushed success_based_routing metrics"); @@ -953,11 +952,7 @@ pub async fn disable_dynamic_routing_algorithm( let db = state.store.as_ref(); let key_manager_state = &state.into(); let timestamp = common_utils::date_time::now_unix_timestamp(); - let profile_id = business_profile - .get_id() - .clone() - .get_string_repr() - .to_owned(); + let profile_id = business_profile.get_id().clone(); let (algorithm_id, dynamic_routing_algorithm, cache_entries_to_redact) = match dynamic_routing_type { routing_types::DynamicRoutingType::SuccessRateBasedRouting => { @@ -1071,9 +1066,8 @@ pub async fn disable_dynamic_routing_algorithm( .await?; core_metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id)]), + router_env::metric_attributes!(("profile_id", profile_id)), ); Ok(ApplicationResponse::Json(response)) @@ -1187,9 +1181,8 @@ where .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; let updated_routing_record = routing_algorithm.foreign_into(); core_metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_owned())]), + router_env::metric_attributes!(("profile_id", profile_id.clone())), ); Ok(ApplicationResponse::Json(updated_routing_record)) } @@ -1268,9 +1261,8 @@ pub async fn default_specific_dynamic_routing_setup( let new_record = record.foreign_into(); core_metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add( - &metrics::CONTEXT, 1, - &add_attributes([("profile_id", profile_id.get_string_repr().to_string())]), + router_env::metric_attributes!(("profile_id", profile_id.clone())), ); Ok(ApplicationResponse::Json(new_record)) } diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 62f1425d4d3c..56e5bc2b0852 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -605,11 +605,7 @@ pub fn validate_dispute_stage_and_dispute_status( common_utils::fp_utils::when( !(dispute_stage_validation && dispute_status_validation), || { - super::metrics::INCOMING_DISPUTE_WEBHOOK_VALIDATION_FAILURE_METRIC.add( - &super::metrics::CONTEXT, - 1, - &[], - ); + super::metrics::INCOMING_DISPUTE_WEBHOOK_VALIDATION_FAILURE_METRIC.add(1, &[]); Err(errors::WebhooksFlowError::DisputeWebhookValidationFailed)? }, ) diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index fe844ef6d731..4b9141c649e9 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -14,7 +14,7 @@ use hyperswitch_domain_models::{ }; use hyperswitch_interfaces::webhooks::{IncomingWebhookFlowError, IncomingWebhookRequestDetails}; use masking::{ExposeInterface, PeekInterface}; -use router_env::{instrument, metrics::add_attributes, tracing, tracing_actix_web::RequestId}; +use router_env::{instrument, tracing, tracing_actix_web::RequestId}; use super::{types, utils, MERCHANT_ID}; use crate::{ @@ -134,12 +134,8 @@ async fn incoming_webhooks_core( let key_manager_state = &(&state).into(); metrics::WEBHOOK_INCOMING_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_account.get_id().get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_account.get_id().clone())), ); let mut request_details = IncomingWebhookRequestDetails { method: req.method().clone(), @@ -200,12 +196,11 @@ async fn incoming_webhooks_core( ); metrics::WEBHOOK_EVENT_TYPE_IDENTIFICATION_FAILURE_COUNT.add( - &metrics::CONTEXT, 1, - &[ - metrics::KeyValue::new(MERCHANT_ID, merchant_account.get_id().clone()), - metrics::KeyValue::new("connector", connector_name.to_string()), - ], + router_env::metric_attributes!( + (MERCHANT_ID, merchant_account.get_id().clone()), + ("connector", connector_name) + ), ); let response = connector @@ -328,12 +323,8 @@ async fn incoming_webhooks_core( if source_verified { metrics::WEBHOOK_SOURCE_VERIFIED_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_account.get_id().clone(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_account.get_id().clone())), ); } else if connector.is_webhook_source_verification_mandatory() { // if webhook consumption is mandatory for connector, fail webhook @@ -498,12 +489,8 @@ async fn incoming_webhooks_core( } } else { metrics::WEBHOOK_INCOMING_FILTERED_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_account.get_id().get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_account.get_id().clone())), ); WebhookResponseTracker::NoEffect }; @@ -661,9 +648,11 @@ async fn payments_incoming_webhook_flow( .unwrap_or(true) => { metrics::WEBHOOK_PAYMENT_NOT_FOUND.add( - &metrics::CONTEXT, 1, - &add_attributes([("merchant_id", merchant_account.get_id().clone())]), + router_env::metric_attributes!(( + "merchant_id", + merchant_account.get_id().clone() + )), ); return Ok(WebhookResponseTracker::NoEffect); } @@ -722,7 +711,7 @@ async fn payouts_incoming_webhook_flow( event_type: webhooks::IncomingWebhookEvent, source_verified: bool, ) -> CustomResult { - metrics::INCOMING_PAYOUT_WEBHOOK_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_PAYOUT_WEBHOOK_METRIC.add(1, &[]); if source_verified { let db = &*state.store; //find payout_attempt by object_reference_id @@ -838,7 +827,7 @@ async fn payouts_incoming_webhook_flow( status: updated_payout_attempt.status, }) } else { - metrics::INCOMING_PAYOUT_WEBHOOK_SIGNATURE_FAILURE_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_PAYOUT_WEBHOOK_SIGNATURE_FAILURE_METRIC.add(1, &[]); Err(report!( errors::ApiErrorResponse::WebhookAuthenticationFailed )) @@ -998,7 +987,7 @@ async fn get_or_update_dispute_object( let db = &*state.store; match option_dispute { None => { - metrics::INCOMING_DISPUTE_WEBHOOK_NEW_RECORD_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_DISPUTE_WEBHOOK_NEW_RECORD_METRIC.add(1, &[]); let dispute_id = generate_id(consts::ID_LENGTH, "dp"); let new_dispute = diesel_models::dispute::DisputeNew { dispute_id, @@ -1034,7 +1023,7 @@ async fn get_or_update_dispute_object( } Some(dispute) => { logger::info!("Dispute Already exists, Updating the dispute details"); - metrics::INCOMING_DISPUTE_WEBHOOK_UPDATE_RECORD_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_DISPUTE_WEBHOOK_UPDATE_RECORD_METRIC.add(1, &[]); let dispute_status = diesel_models::enums::DisputeStatus::foreign_try_from(event_type) .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) .attach_printable("event type to dispute state conversion failure")?; @@ -1449,7 +1438,7 @@ async fn disputes_incoming_webhook_flow( request_details: &IncomingWebhookRequestDetails<'_>, event_type: webhooks::IncomingWebhookEvent, ) -> CustomResult { - metrics::INCOMING_DISPUTE_WEBHOOK_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_DISPUTE_WEBHOOK_METRIC.add(1, &[]); if source_verified { let db = &*state.store; let dispute_details = connector.get_dispute_details(request_details).switch()?; @@ -1495,14 +1484,14 @@ async fn disputes_incoming_webhook_flow( Some(dispute_object.created_at), )) .await?; - metrics::INCOMING_DISPUTE_WEBHOOK_MERCHANT_NOTIFIED_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_DISPUTE_WEBHOOK_MERCHANT_NOTIFIED_METRIC.add(1, &[]); Ok(WebhookResponseTracker::Dispute { dispute_id: dispute_object.dispute_id, payment_id: dispute_object.payment_id, status: dispute_object.dispute_status, }) } else { - metrics::INCOMING_DISPUTE_WEBHOOK_SIGNATURE_FAILURE_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::INCOMING_DISPUTE_WEBHOOK_SIGNATURE_FAILURE_METRIC.add(1, &[]); Err(report!( errors::ApiErrorResponse::WebhookAuthenticationFailed )) diff --git a/crates/router/src/core/webhooks/incoming_v2.rs b/crates/router/src/core/webhooks/incoming_v2.rs index b91a6f0e9a01..d331e4d67f3d 100644 --- a/crates/router/src/core/webhooks/incoming_v2.rs +++ b/crates/router/src/core/webhooks/incoming_v2.rs @@ -12,7 +12,7 @@ use hyperswitch_domain_models::{ router_response_types::{VerifyWebhookSourceResponseData, VerifyWebhookStatus}, }; use hyperswitch_interfaces::webhooks::IncomingWebhookRequestDetails; -use router_env::{instrument, metrics::add_attributes, tracing, tracing_actix_web::RequestId}; +use router_env::{instrument, tracing, tracing_actix_web::RequestId}; use super::{types, utils, MERCHANT_ID}; use crate::{ @@ -126,12 +126,8 @@ async fn incoming_webhooks_core( serde_json::Value, )> { metrics::WEBHOOK_INCOMING_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_account.get_id().get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_account.get_id().clone())), ); let mut request_details = IncomingWebhookRequestDetails { method: req.method().clone(), @@ -183,12 +179,11 @@ async fn incoming_webhooks_core( ); metrics::WEBHOOK_EVENT_TYPE_IDENTIFICATION_FAILURE_COUNT.add( - &metrics::CONTEXT, 1, - &[ - metrics::KeyValue::new(MERCHANT_ID, merchant_account.get_id().clone()), - metrics::KeyValue::new("connector", connector_name.to_string()), - ], + router_env::metric_attributes!( + (MERCHANT_ID, merchant_account.get_id().clone()), + ("connector", connector_name) + ), ); let response = connector @@ -288,12 +283,8 @@ async fn incoming_webhooks_core( if source_verified { metrics::WEBHOOK_SOURCE_VERIFIED_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_account.get_id().clone(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_account.get_id().clone())), ); } @@ -356,12 +347,8 @@ async fn incoming_webhooks_core( } } else { metrics::WEBHOOK_INCOMING_FILTERED_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_account.get_id().get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_account.get_id().clone())), ); WebhookResponseTracker::NoEffect }; @@ -476,9 +463,11 @@ async fn payments_incoming_webhook_flow( .unwrap_or(true) => { metrics::WEBHOOK_PAYMENT_NOT_FOUND.add( - &metrics::CONTEXT, 1, - &add_attributes([("merchant_id", merchant_account.get_id().clone())]), + router_env::metric_attributes!(( + "merchant_id", + merchant_account.get_id().clone() + )), ); return Ok(WebhookResponseTracker::NoEffect); } diff --git a/crates/router/src/core/webhooks/outgoing.rs b/crates/router/src/core/webhooks/outgoing.rs index 0a9c17ed3a07..16d927be2682 100644 --- a/crates/router/src/core/webhooks/outgoing.rs +++ b/crates/router/src/core/webhooks/outgoing.rs @@ -17,7 +17,6 @@ use hyperswitch_interfaces::consts; use masking::{ExposeInterface, Mask, PeekInterface, Secret}; use router_env::{ instrument, - metrics::add_attributes, tracing::{self, Instrument}, }; @@ -292,12 +291,8 @@ async fn trigger_webhook_to_merchant( .await; metrics::WEBHOOK_OUTGOING_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - business_profile.merchant_id.get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, business_profile.merchant_id.clone())), ); logger::debug!(outgoing_webhook_response=?response); @@ -561,21 +556,14 @@ pub(crate) async fn add_outgoing_webhook_retry_task_to_process_tracker( ) .map_err(errors::StorageError::from)?; + let attributes = router_env::metric_attributes!(("flow", "OutgoingWebhookRetry")); match db.insert_process(process_tracker_entry).await { Ok(process_tracker) => { - crate::routes::metrics::TASKS_ADDED_COUNT.add( - &metrics::CONTEXT, - 1, - &add_attributes([("flow", "OutgoingWebhookRetry")]), - ); + crate::routes::metrics::TASKS_ADDED_COUNT.add(1, attributes); Ok(process_tracker) } Err(error) => { - crate::routes::metrics::TASK_ADDITION_FAILURES_COUNT.add( - &metrics::CONTEXT, - 1, - &add_attributes([("flow", "OutgoingWebhookRetry")]), - ); + crate::routes::metrics::TASK_ADDITION_FAILURES_COUNT.add(1, attributes); Err(error) } } @@ -848,12 +836,8 @@ async fn update_event_in_storage( fn increment_webhook_outgoing_received_count(merchant_id: &common_utils::id_type::MerchantId) { metrics::WEBHOOK_OUTGOING_RECEIVED_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_id.get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_id.clone())), ) } @@ -887,12 +871,8 @@ async fn error_response_handler( schedule_webhook_retry: ScheduleWebhookRetry, ) -> CustomResult<(), errors::WebhooksFlowError> { metrics::WEBHOOK_OUTGOING_NOT_RECEIVED_COUNT.add( - &metrics::CONTEXT, 1, - &[metrics::KeyValue::new( - MERCHANT_ID, - merchant_id.get_string_repr().to_owned(), - )], + router_env::metric_attributes!((MERCHANT_ID, merchant_id.clone())), ); let error = report!(errors::WebhooksFlowError::NotReceivedByMerchant); diff --git a/crates/router/src/routes/health.rs b/crates/router/src/routes/health.rs index 0f2e63336470..7e9de917be38 100644 --- a/crates/router/src/routes/health.rs +++ b/crates/router/src/routes/health.rs @@ -14,7 +14,7 @@ use crate::{ #[instrument(skip_all, fields(flow = ?Flow::HealthCheck))] // #[actix_web::get("/health")] pub async fn health() -> impl actix_web::Responder { - metrics::HEALTH_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::HEALTH_METRIC.add(1, &[]); logger::info!("Health was called"); actix_web::HttpResponse::Ok().body("health is good") @@ -25,7 +25,7 @@ pub async fn deep_health_check( state: web::Data, request: HttpRequest, ) -> impl actix_web::Responder { - metrics::HEALTH_METRIC.add(&metrics::CONTEXT, 1, &[]); + metrics::HEALTH_METRIC.add(1, &[]); let flow = Flow::DeepHealthCheck; diff --git a/crates/router/src/routes/metrics.rs b/crates/router/src/routes/metrics.rs index 1b55c838c45e..5920c001d3f4 100644 --- a/crates/router/src/routes/metrics.rs +++ b/crates/router/src/routes/metrics.rs @@ -2,9 +2,8 @@ pub mod bg_metrics_collector; pub mod request; pub mod utils; -use router_env::{counter_metric, global_meter, histogram_metric, metrics_context}; +use router_env::{counter_metric, global_meter, histogram_metric_f64}; -metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); counter_metric!(HEALTH_METRIC, GLOBAL_METER); // No. of health API hits @@ -13,8 +12,8 @@ counter_metric!(KV_MISS, GLOBAL_METER); // No. of KV misses // API Level Metrics counter_metric!(REQUESTS_RECEIVED, GLOBAL_METER); counter_metric!(REQUEST_STATUS, GLOBAL_METER); -histogram_metric!(REQUEST_TIME, GLOBAL_METER); -histogram_metric!(EXTERNAL_REQUEST_TIME, GLOBAL_METER); +histogram_metric_f64!(REQUEST_TIME, GLOBAL_METER); +histogram_metric_f64!(EXTERNAL_REQUEST_TIME, GLOBAL_METER); // Operation Level Metrics counter_metric!(PAYMENT_OPS_COUNT, GLOBAL_METER); @@ -22,7 +21,7 @@ counter_metric!(PAYMENT_OPS_COUNT, GLOBAL_METER); counter_metric!(PAYMENT_COUNT, GLOBAL_METER); counter_metric!(SUCCESSFUL_PAYMENT, GLOBAL_METER); //TODO: This can be removed, added for payment list debugging -histogram_metric!(PAYMENT_LIST_LATENCY, GLOBAL_METER); +histogram_metric_f64!(PAYMENT_LIST_LATENCY, GLOBAL_METER); counter_metric!(REFUND_COUNT, GLOBAL_METER); counter_metric!(SUCCESSFUL_REFUND, GLOBAL_METER); @@ -58,7 +57,7 @@ counter_metric!(MCA_CREATE, GLOBAL_METER); // Flow Specific Metrics -histogram_metric!(CONNECTOR_REQUEST_TIME, GLOBAL_METER); +histogram_metric_f64!(CONNECTOR_REQUEST_TIME, GLOBAL_METER); counter_metric!(SESSION_TOKEN_CREATED, GLOBAL_METER); counter_metric!(CONNECTOR_CALL_COUNT, GLOBAL_METER); // Attributes needed @@ -89,9 +88,9 @@ counter_metric!(CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT, GLOBAL_METER); counter_metric!(CARD_LOCKER_FAILURES, GLOBAL_METER); counter_metric!(CARD_LOCKER_SUCCESSFUL_RESPONSE, GLOBAL_METER); counter_metric!(TEMP_LOCKER_FAILURES, GLOBAL_METER); -histogram_metric!(CARD_ADD_TIME, GLOBAL_METER); -histogram_metric!(CARD_GET_TIME, GLOBAL_METER); -histogram_metric!(CARD_DELETE_TIME, GLOBAL_METER); +histogram_metric_f64!(CARD_ADD_TIME, GLOBAL_METER); +histogram_metric_f64!(CARD_GET_TIME, GLOBAL_METER); +histogram_metric_f64!(CARD_DELETE_TIME, GLOBAL_METER); // Apple Pay Flow Metrics counter_metric!(APPLE_PAY_MANUAL_FLOW, GLOBAL_METER); @@ -138,7 +137,7 @@ counter_metric!(ACCESS_TOKEN_CACHE_MISS, GLOBAL_METER); counter_metric!(INTEGRITY_CHECK_FAILED, GLOBAL_METER); // Network Tokenization metrics -histogram_metric!(GENERATE_NETWORK_TOKEN_TIME, GLOBAL_METER); -histogram_metric!(FETCH_NETWORK_TOKEN_TIME, GLOBAL_METER); -histogram_metric!(DELETE_NETWORK_TOKEN_TIME, GLOBAL_METER); -histogram_metric!(CHECK_NETWORK_TOKEN_STATUS_TIME, GLOBAL_METER); +histogram_metric_f64!(GENERATE_NETWORK_TOKEN_TIME, GLOBAL_METER); +histogram_metric_f64!(FETCH_NETWORK_TOKEN_TIME, GLOBAL_METER); +histogram_metric_f64!(DELETE_NETWORK_TOKEN_TIME, GLOBAL_METER); +histogram_metric_f64!(CHECK_NETWORK_TOKEN_STATUS_TIME, GLOBAL_METER); diff --git a/crates/router/src/routes/metrics/request.rs b/crates/router/src/routes/metrics/request.rs index 572f3dc93302..c2d49cd7ae44 100644 --- a/crates/router/src/routes/metrics/request.rs +++ b/crates/router/src/routes/metrics/request.rs @@ -1,5 +1,3 @@ -use router_env::metrics::add_attributes; - use super::utils as metric_utils; use crate::services::ApplicationResponse; @@ -11,16 +9,11 @@ where F: futures::Future, { let key = "request_type"; - super::REQUESTS_RECEIVED.add( - &super::CONTEXT, - 1, - &add_attributes([(key, flow.to_string())]), - ); + super::REQUESTS_RECEIVED.add(1, router_env::metric_attributes!((key, flow.to_string()))); let (result, time) = metric_utils::time_future(future).await; super::REQUEST_TIME.record( - &super::CONTEXT, time.as_secs_f64(), - &add_attributes([(key, flow.to_string())]), + router_env::metric_attributes!((key, flow.to_string())), ); result } @@ -31,13 +24,12 @@ pub fn status_code_metrics( merchant_id: common_utils::id_type::MerchantId, ) { super::REQUEST_STATUS.add( - &super::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("status_code", status_code), ("flow", flow), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ) } diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 9416ff175a85..a4c1cac0ac43 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -46,7 +46,7 @@ pub use hyperswitch_interfaces::{ }, }; use masking::{Maskable, PeekInterface}; -use router_env::{instrument, metrics::add_attributes, tracing, tracing_actix_web::RequestId, Tag}; +use router_env::{instrument, tracing, tracing_actix_web::RequestId, Tag}; use serde::Serialize; use serde_json::json; use tera::{Context, Error as TeraError, Tera}; @@ -164,9 +164,8 @@ where } payments::CallConnectorAction::Trigger => { metrics::CONNECTOR_CALL_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("connector", req.connector.to_string()), ( "flow", @@ -174,9 +173,8 @@ where .split("::") .last() .unwrap_or_default() - .to_string(), ), - ]), + ), ); let connector_request = match connector_request { @@ -190,9 +188,11 @@ where | &errors::ConnectorError::RequestEncodingFailedWithReason(_) ) { metrics::REQUEST_BUILD_FAILURE.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", req.connector.to_string())]), + router_env::metric_attributes!(( + "connector", + req.connector.clone() + )), ) } })?, @@ -254,12 +254,12 @@ where == &errors::ConnectorError::ResponseDeserializationFailed { metrics::RESPONSE_DESERIALIZATION_FAILURE.add( - &metrics::CONTEXT, + 1, - &add_attributes([( + router_env::metric_attributes!(( "connector", - req.connector.to_string(), - )]), + req.connector.clone(), + )), ) } }); @@ -294,9 +294,11 @@ where .map_or(external_latency, |val| val + external_latency), ); metrics::CONNECTOR_ERROR_RESPONSE_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([("connector", req.connector.clone())]), + router_env::metric_attributes!(( + "connector", + req.connector.clone(), + )), ); let error = match body.status_code { @@ -436,10 +438,10 @@ pub async fn send_request( )?; let headers = request.headers.construct_header_map()?; - let metrics_tag = router_env::opentelemetry::KeyValue { - key: consts::METRICS_HOST_TAG_NAME.into(), - value: url.host_str().unwrap_or_default().to_string().into(), - }; + let metrics_tag = router_env::metric_attributes!(( + consts::METRICS_HOST_TAG_NAME, + url.host_str().unwrap_or_default().to_owned() + )); let request = { match request.method { Method::Get => client.get(url), @@ -503,11 +505,11 @@ pub async fn send_request( .await .map_err(|error| match error { error if error.is_timeout() => { - metrics::REQUEST_BUILD_FAILURE.add(&metrics::CONTEXT, 1, &[]); + metrics::REQUEST_BUILD_FAILURE.add(1, &[]); errors::ApiClientError::RequestTimeoutReceived } error if is_connection_closed_before_message_could_complete(&error) => { - metrics::REQUEST_BUILD_FAILURE.add(&metrics::CONTEXT, 1, &[]); + metrics::REQUEST_BUILD_FAILURE.add(1, &[]); errors::ApiClientError::ConnectionClosedIncompleteMessage } _ => errors::ApiClientError::RequestNotSent(error.to_string()), @@ -521,11 +523,11 @@ pub async fn send_request( .await .map_err(|error| match error { error if error.is_timeout() => { - metrics::REQUEST_BUILD_FAILURE.add(&metrics::CONTEXT, 1, &[]); + metrics::REQUEST_BUILD_FAILURE.add(1, &[]); errors::ApiClientError::RequestTimeoutReceived } error if is_connection_closed_before_message_could_complete(&error) => { - metrics::REQUEST_BUILD_FAILURE.add(&metrics::CONTEXT, 1, &[]); + metrics::REQUEST_BUILD_FAILURE.add(1, &[]); errors::ApiClientError::ConnectionClosedIncompleteMessage } _ => errors::ApiClientError::RequestNotSent(error.to_string()), @@ -536,8 +538,7 @@ pub async fn send_request( let response = common_utils::metrics::utils::record_operation_time( send_request, &metrics::EXTERNAL_REQUEST_TIME, - &metrics::CONTEXT, - &[metrics_tag.clone()], + metrics_tag, ) .await; // Retry once if the response is connection closed. @@ -555,7 +556,7 @@ pub async fn send_request( if error.current_context() == &errors::ApiClientError::ConnectionClosedIncompleteMessage => { - metrics::AUTO_RETRY_CONNECTION_CLOSED.add(&metrics::CONTEXT, 1, &[]); + metrics::AUTO_RETRY_CONNECTION_CLOSED.add(1, &[]); match cloned_send_request { Some(cloned_request) => { logger::info!( @@ -564,8 +565,7 @@ pub async fn send_request( common_utils::metrics::utils::record_operation_time( cloned_request, &metrics::EXTERNAL_REQUEST_TIME, - &metrics::CONTEXT, - &[metrics_tag], + metrics_tag, ) .await } diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index f465719949aa..e8435243ff4d 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -600,7 +600,7 @@ where } let report_failure = || { - metrics::PARTIAL_AUTH_FAILURE.add(&metrics::CONTEXT, 1, &[]); + metrics::PARTIAL_AUTH_FAILURE.add(1, &[]); }; let payload = ExtractedPayload::from_headers(request_headers) diff --git a/crates/router/src/services/authentication/decision.rs b/crates/router/src/services/authentication/decision.rs index 4ff9f8401baa..a1796f97c3b2 100644 --- a/crates/router/src/services/authentication/decision.rs +++ b/crates/router/src/services/authentication/decision.rs @@ -1,6 +1,5 @@ use common_utils::{errors::CustomResult, request::RequestContent}; use masking::{ErasedMaskSerialize, Secret}; -use router_env::opentelemetry::KeyValue; use serde::Serialize; use storage_impl::errors::ApiClientError; @@ -197,19 +196,13 @@ where E: std::fmt::Debug, F: futures::Future> + Send + 'static, { - metrics::API_KEY_REQUEST_INITIATED.add( - &metrics::CONTEXT, - 1, - &[KeyValue::new("type", request_type)], - ); + metrics::API_KEY_REQUEST_INITIATED + .add(1, router_env::metric_attributes!(("type", request_type))); tokio::spawn(async move { match future.await { Ok(_) => { - metrics::API_KEY_REQUEST_COMPLETED.add( - &metrics::CONTEXT, - 1, - &[KeyValue::new("type", request_type)], - ); + metrics::API_KEY_REQUEST_COMPLETED + .add(1, router_env::metric_attributes!(("type", request_type))); } Err(e) => { router_env::error!("Error in tracked job: {:?}", e); diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index 9dca6cf34778..e4046f95a153 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -38,7 +38,6 @@ use hyperswitch_domain_models::payments::PaymentIntent; use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; use masking::{ExposeInterface, SwitchStrategy}; use nanoid::nanoid; -use router_env::metrics::add_attributes; use serde::de::DeserializeOwned; use serde_json::Value; use tracing_futures::Instrument; @@ -678,11 +677,8 @@ pub fn handle_json_response_deserialization_failure( res: types::Response, connector: &'static str, ) -> CustomResult { - metrics::RESPONSE_DESERIALIZATION_FAILURE.add( - &metrics::CONTEXT, - 1, - &add_attributes([("connector", connector)]), - ); + metrics::RESPONSE_DESERIALIZATION_FAILURE + .add(1, router_env::metric_attributes!(("connector", connector))); let response_data = String::from_utf8(res.response.to_vec()) .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; @@ -726,21 +722,11 @@ pub fn add_connector_http_status_code_metrics(option_status_code: Option) { if let Some(status_code) = option_status_code { let status_code_type = get_http_status_code_type(status_code).ok(); match status_code_type.as_deref() { - Some("1xx") => { - metrics::CONNECTOR_HTTP_STATUS_CODE_1XX_COUNT.add(&metrics::CONTEXT, 1, &[]) - } - Some("2xx") => { - metrics::CONNECTOR_HTTP_STATUS_CODE_2XX_COUNT.add(&metrics::CONTEXT, 1, &[]) - } - Some("3xx") => { - metrics::CONNECTOR_HTTP_STATUS_CODE_3XX_COUNT.add(&metrics::CONTEXT, 1, &[]) - } - Some("4xx") => { - metrics::CONNECTOR_HTTP_STATUS_CODE_4XX_COUNT.add(&metrics::CONTEXT, 1, &[]) - } - Some("5xx") => { - metrics::CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT.add(&metrics::CONTEXT, 1, &[]) - } + Some("1xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_1XX_COUNT.add(1, &[]), + Some("2xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_2XX_COUNT.add(1, &[]), + Some("3xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_3XX_COUNT.add(1, &[]), + Some("4xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_4XX_COUNT.add(1, &[]), + Some("5xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT.add(1, &[]), _ => logger::info!("Skip metrics as invalid http status code received from connector"), }; } else { @@ -1049,26 +1035,24 @@ pub fn add_apple_pay_flow_metrics( if let Some(flow) = apple_pay_flow { match flow { domain::ApplePayFlow::Simplified(_) => metrics::APPLE_PAY_SIMPLIFIED_FLOW.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ), domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ), } } @@ -1085,28 +1069,26 @@ pub fn add_apple_pay_payment_status_metrics( match flow { domain::ApplePayFlow::Simplified(_) => { metrics::APPLE_PAY_SIMPLIFIED_FLOW_SUCCESSFUL_PAYMENT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ) } domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW_SUCCESSFUL_PAYMENT .add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ), } } @@ -1115,27 +1097,25 @@ pub fn add_apple_pay_payment_status_metrics( match flow { domain::ApplePayFlow::Simplified(_) => { metrics::APPLE_PAY_SIMPLIFIED_FLOW_FAILED_PAYMENT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ) } domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW_FAILED_PAYMENT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ( "connector", connector.to_owned().unwrap_or("null".to_string()), ), - ("merchant_id", merchant_id.get_string_repr().to_owned()), - ]), + ("merchant_id", merchant_id.clone()), + ), ), } } diff --git a/crates/router/src/utils/db_utils.rs b/crates/router/src/utils/db_utils.rs index 67641a3fe7b1..07ec03f4de46 100644 --- a/crates/router/src/utils/db_utils.rs +++ b/crates/router/src/utils/db_utils.rs @@ -28,7 +28,7 @@ where Ok(output) => Ok(output), Err(redis_error) => match redis_error.current_context() { redis_interface::errors::RedisError::NotFound => { - metrics::KV_MISS.add(&metrics::CONTEXT, 1, &[]); + metrics::KV_MISS.add(1, &[]); database_call_closure().await } // Keeping the key empty here since the error would never go here. @@ -74,7 +74,7 @@ where }), (Err(redis_error), _) => match redis_error.current_context() { redis_interface::errors::RedisError::NotFound => { - metrics::KV_MISS.add(&metrics::CONTEXT, 1, &[]); + metrics::KV_MISS.add(1, &[]); database_call().await } // Keeping the key empty here since the error would never go here. diff --git a/crates/router/src/workflows/api_key_expiry.rs b/crates/router/src/workflows/api_key_expiry.rs index c04e4c5d576c..bf6100179bf2 100644 --- a/crates/router/src/workflows/api_key_expiry.rs +++ b/crates/router/src/workflows/api_key_expiry.rs @@ -2,7 +2,7 @@ use common_utils::{errors::ValidationError, ext_traits::ValueExt}; use diesel_models::{ enums as storage_enums, process_tracker::business_status, ApiKeyExpiryTrackingData, }; -use router_env::{logger, metrics::add_attributes}; +use router_env::logger; use scheduler::{workflows::ProcessTrackerWorkflow, SchedulerSessionState}; use crate::{ @@ -134,11 +134,8 @@ impl ProcessTrackerWorkflow for ApiKeyExpiryWorkflow { db.process_tracker_update_process_status_by_ids(task_ids, updated_process_tracker_data) .await?; // Remaining tasks are re-scheduled, so will be resetting the added count - metrics::TASKS_RESET_COUNT.add( - &metrics::CONTEXT, - 1, - &add_attributes([("flow", "ApiKeyExpiry")]), - ); + metrics::TASKS_RESET_COUNT + .add(1, router_env::metric_attributes!(("flow", "ApiKeyExpiry"))); } Ok(()) diff --git a/crates/router_env/Cargo.toml b/crates/router_env/Cargo.toml index 27fe451b753f..8a3482a0ac53 100644 --- a/crates/router_env/Cargo.toml +++ b/crates/router_env/Cargo.toml @@ -13,8 +13,10 @@ config = { version = "0.14.0", features = ["toml"] } error-stack = "0.4.1" gethostname = "0.4.3" once_cell = "1.19.0" -opentelemetry = { version = "0.19.0", features = ["rt-tokio-current-thread", "metrics"] } -opentelemetry-otlp = { version = "0.12.0", features = ["metrics"] } +opentelemetry = { version = "0.27.1", default-features = false, features = ["internal-logs", "metrics", "trace"] } +opentelemetry-aws = { version = "0.15.0", default-features = false, features = ["internal-logs", "trace"] } +opentelemetry-otlp = { version = "0.27.0", default-features = false, features = ["grpc-tonic", "metrics", "trace"] } +opentelemetry_sdk = { version = "0.27.1", default-features = false, features = ["rt-tokio-current-thread", "metrics", "trace"] } rustc-hash = "1.1" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" @@ -23,10 +25,10 @@ strum = { version = "0.26.2", features = ["derive"] } time = { version = "0.3.35", default-features = false, features = ["formatting"] } tokio = { version = "1.37.0" } tracing = { workspace = true } -tracing-actix-web = { version = "0.7.10", features = ["opentelemetry_0_19", "uuid_v7"], optional = true } +tracing-actix-web = { version = "0.7.15", features = ["opentelemetry_0_27", "uuid_v7"], optional = true } tracing-appender = { version = "0.2.3" } tracing-attributes = "0.1.27" -tracing-opentelemetry = { version = "0.19.0" } +tracing-opentelemetry = { version = "0.28.0", default-features = false } tracing-subscriber = { version = "0.3.18", default-features = true, features = ["env-filter", "json", "registry"] } vergen = { version = "8.3.1", optional = true, features = ["cargo", "git", "git2", "rustc"] } diff --git a/crates/router_env/src/logger/setup.rs b/crates/router_env/src/logger/setup.rs index 6433172edf4d..7447c8787e06 100644 --- a/crates/router_env/src/logger/setup.rs +++ b/crates/router_env/src/logger/setup.rs @@ -3,20 +3,6 @@ use std::time::Duration; use ::config::ConfigError; -use opentelemetry::{ - global, runtime, - sdk::{ - export::metrics::aggregation::cumulative_temporality_selector, - metrics::{controllers::BasicController, selectors::simple}, - propagation::TraceContextPropagator, - trace, - trace::BatchConfig, - Resource, - }, - trace::{TraceContextExt, TraceState}, - KeyValue, -}; -use opentelemetry_otlp::{TonicExporterBuilder, WithExportConfig}; use serde_json::ser::{CompactFormatter, PrettyFormatter}; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::{fmt, prelude::*, util::SubscriberInitExt, EnvFilter, Layer}; @@ -27,7 +13,6 @@ use crate::{config, FormattingLayer, StorageSubscription}; #[derive(Debug)] pub struct TelemetryGuard { _log_guards: Vec, - _metrics_controller: Option, } /// Setup logging sub-system specifying the logging configuration, service (binary) name, and a @@ -47,10 +32,9 @@ pub fn setup( } else { None }; - let _metrics_controller = if config.telemetry.metrics_enabled { + + if config.telemetry.metrics_enabled { setup_metrics_pipeline(&config.telemetry) - } else { - None }; // Setup file logging @@ -132,21 +116,23 @@ pub fn setup( // dropped Ok(TelemetryGuard { _log_guards: guards, - _metrics_controller, }) } -fn get_opentelemetry_exporter(config: &config::LogTelemetry) -> TonicExporterBuilder { - let mut exporter_builder = opentelemetry_otlp::new_exporter().tonic(); +fn get_opentelemetry_exporter_config( + config: &config::LogTelemetry, +) -> opentelemetry_otlp::ExportConfig { + let mut exporter_config = opentelemetry_otlp::ExportConfig { + protocol: opentelemetry_otlp::Protocol::Grpc, + endpoint: config.otel_exporter_otlp_endpoint.clone(), + ..Default::default() + }; - if let Some(ref endpoint) = config.otel_exporter_otlp_endpoint { - exporter_builder = exporter_builder.with_endpoint(endpoint); - } if let Some(timeout) = config.otel_exporter_otlp_timeout { - exporter_builder = exporter_builder.with_timeout(Duration::from_millis(timeout)); + exporter_config.timeout = Duration::from_millis(timeout); } - exporter_builder + exporter_config } #[derive(Debug, Clone)] @@ -192,39 +178,41 @@ impl TraceAssertion { /// Conditional Sampler for providing control on url based tracing #[derive(Clone, Debug)] -struct ConditionalSampler(TraceAssertion, T); +struct ConditionalSampler( + TraceAssertion, + T, +); -impl trace::ShouldSample for ConditionalSampler { +impl + opentelemetry_sdk::trace::ShouldSample for ConditionalSampler +{ fn should_sample( &self, parent_context: Option<&opentelemetry::Context>, trace_id: opentelemetry::trace::TraceId, name: &str, span_kind: &opentelemetry::trace::SpanKind, - attributes: &opentelemetry::trace::OrderMap, + attributes: &[opentelemetry::KeyValue], links: &[opentelemetry::trace::Link], - instrumentation_library: &opentelemetry::InstrumentationLibrary, ) -> opentelemetry::trace::SamplingResult { + use opentelemetry::trace::TraceContextExt; + match attributes - .get(&opentelemetry::Key::new("http.route")) + .iter() + .find(|&kv| kv.key == opentelemetry::Key::new("http.route")) .map_or(self.0.default, |inner| { - self.0.should_trace_url(&inner.as_str()) + self.0.should_trace_url(&inner.value.as_str()) }) { - true => self.1.should_sample( - parent_context, - trace_id, - name, - span_kind, - attributes, - links, - instrumentation_library, - ), + true => { + self.1 + .should_sample(parent_context, trace_id, name, span_kind, attributes, links) + } false => opentelemetry::trace::SamplingResult { decision: opentelemetry::trace::SamplingDecision::Drop, attributes: Vec::new(), trace_state: match parent_context { Some(ctx) => ctx.span().span_context().trace_state().clone(), - None => TraceState::default(), + None => opentelemetry::trace::TraceState::default(), }, }, } @@ -234,95 +222,117 @@ impl trace::ShouldSample for Condition fn setup_tracing_pipeline( config: &config::LogTelemetry, service_name: &str, -) -> Option> -{ - global::set_text_map_propagator(TraceContextPropagator::new()); +) -> Option< + tracing_opentelemetry::OpenTelemetryLayer< + tracing_subscriber::Registry, + opentelemetry_sdk::trace::Tracer, + >, +> { + use opentelemetry::trace::TracerProvider; + use opentelemetry_otlp::WithExportConfig; + use opentelemetry_sdk::trace; + + opentelemetry::global::set_text_map_propagator( + opentelemetry_sdk::propagation::TraceContextPropagator::new(), + ); + + // Set the export interval to 1 second + let batch_config = trace::BatchConfigBuilder::default() + .with_scheduled_delay(Duration::from_millis(1000)) + .build(); + + let exporter_result = opentelemetry_otlp::SpanExporter::builder() + .with_tonic() + .with_export_config(get_opentelemetry_exporter_config(config)) + .build(); + + let exporter = if config.ignore_errors { + #[allow(clippy::print_stderr)] // The logger hasn't been initialized yet + exporter_result + .inspect_err(|error| eprintln!("Failed to build traces exporter: {error:?}")) + .ok()? + } else { + // Safety: This is conditional, there is an option to avoid this behavior at runtime. + #[allow(clippy::expect_used)] + exporter_result.expect("Failed to build traces exporter") + }; - let mut trace_config = trace::config() + let mut provider_builder = trace::TracerProvider::builder() + .with_span_processor( + trace::BatchSpanProcessor::builder( + exporter, + // The runtime would have to be updated if a different web framework is used + opentelemetry_sdk::runtime::TokioCurrentThread, + ) + .with_batch_config(batch_config) + .build(), + ) .with_sampler(trace::Sampler::ParentBased(Box::new(ConditionalSampler( TraceAssertion { clauses: config .route_to_trace .clone() - .map(|inner| inner.into_iter().map(Into::into).collect()), + .map(|inner| inner.into_iter().map(TraceUrlAssert::from).collect()), default: false, }, trace::Sampler::TraceIdRatioBased(config.sampling_rate.unwrap_or(1.0)), )))) - .with_resource(Resource::new(vec![KeyValue::new( - "service.name", - service_name.to_owned(), - )])); + .with_resource(opentelemetry_sdk::Resource::new(vec![ + opentelemetry::KeyValue::new("service.name", service_name.to_owned()), + ])); + if config.use_xray_generator { - trace_config = trace_config.with_id_generator(trace::XrayIdGenerator::default()); + provider_builder = provider_builder + .with_id_generator(opentelemetry_aws::trace::XrayIdGenerator::default()); } - // Change the default export interval from 5 seconds to 1 second - let batch_config = BatchConfig::default().with_scheduled_delay(Duration::from_millis(1000)); - - let traces_layer_result = opentelemetry_otlp::new_pipeline() - .tracing() - .with_exporter(get_opentelemetry_exporter(config)) - .with_batch_config(batch_config) - .with_trace_config(trace_config) - .install_batch(runtime::TokioCurrentThread) - .map(|tracer| tracing_opentelemetry::layer().with_tracer(tracer)); - - #[allow(clippy::print_stderr)] // The logger hasn't been initialized yet - if config.ignore_errors { - traces_layer_result - .map_err(|error| { - eprintln!("Failed to create an `opentelemetry_otlp` tracer: {error:?}") - }) - .ok() - } else { - // Safety: This is conditional, there is an option to avoid this behavior at runtime. - #[allow(clippy::expect_used)] - Some(traces_layer_result.expect("Failed to create an `opentelemetry_otlp` tracer")) - } + Some( + tracing_opentelemetry::layer() + .with_tracer(provider_builder.build().tracer(service_name.to_owned())), + ) } -fn setup_metrics_pipeline(config: &config::LogTelemetry) -> Option { - let histogram_buckets = { - let mut init = 0.01; - let mut buckets: [f64; 15] = [0.0; 15]; - - for bucket in &mut buckets { - init *= 2.0; - *bucket = init; - } - buckets - }; +fn setup_metrics_pipeline(config: &config::LogTelemetry) { + use opentelemetry_otlp::WithExportConfig; - let metrics_controller_result = opentelemetry_otlp::new_pipeline() - .metrics( - simple::histogram(histogram_buckets), - cumulative_temporality_selector(), - // This would have to be updated if a different web framework is used - runtime::TokioCurrentThread, - ) - .with_exporter(get_opentelemetry_exporter(config)) - .with_period(Duration::from_secs(3)) - .with_timeout(Duration::from_secs(10)) - .with_resource(Resource::new(vec![KeyValue::new( - "pod", - std::env::var("POD_NAME").map_or( - "hyperswitch-server-default".into(), - Into::::into, - ), - )])) + let exporter_result = opentelemetry_otlp::MetricExporter::builder() + .with_tonic() + .with_temporality(opentelemetry_sdk::metrics::Temporality::Cumulative) + .with_export_config(get_opentelemetry_exporter_config(config)) .build(); - #[allow(clippy::print_stderr)] // The logger hasn't been initialized yet - if config.ignore_errors { - metrics_controller_result - .map_err(|error| eprintln!("Failed to setup metrics pipeline: {error:?}")) - .ok() + let exporter = if config.ignore_errors { + #[allow(clippy::print_stderr)] // The logger hasn't been initialized yet + exporter_result + .inspect_err(|error| eprintln!("Failed to build metrics exporter: {error:?}")) + .ok(); + return; } else { // Safety: This is conditional, there is an option to avoid this behavior at runtime. #[allow(clippy::expect_used)] - Some(metrics_controller_result.expect("Failed to setup metrics pipeline")) - } + exporter_result.expect("Failed to build metrics exporter") + }; + + let reader = opentelemetry_sdk::metrics::PeriodicReader::builder( + exporter, + // The runtime would have to be updated if a different web framework is used + opentelemetry_sdk::runtime::TokioCurrentThread, + ) + .with_interval(Duration::from_secs(3)) + .with_timeout(Duration::from_secs(10)) + .build(); + + let provider = opentelemetry_sdk::metrics::SdkMeterProvider::builder() + .with_reader(reader) + .with_resource(opentelemetry_sdk::Resource::new([ + opentelemetry::KeyValue::new( + "pod", + std::env::var("POD_NAME").unwrap_or(String::from("hyperswitch-server-default")), + ), + ])) + .build(); + + opentelemetry::global::set_meter_provider(provider); } fn get_envfilter( diff --git a/crates/router_env/src/metrics.rs b/crates/router_env/src/metrics.rs index 780c010579f7..9a7efff04948 100644 --- a/crates/router_env/src/metrics.rs +++ b/crates/router_env/src/metrics.rs @@ -1,16 +1,5 @@ //! Utilities to easily create opentelemetry contexts, meters and metrics. -/// Create a metrics [`Context`][Context] with the specified name. -/// -/// [Context]: opentelemetry::Context -#[macro_export] -macro_rules! metrics_context { - ($name:ident) => { - pub(crate) static $name: once_cell::sync::Lazy<$crate::opentelemetry::Context> = - once_cell::sync::Lazy::new($crate::opentelemetry::Context::current); - }; -} - /// Create a global [`Meter`][Meter] with the specified name and an optional description. /// /// [Meter]: opentelemetry::metrics::Meter @@ -20,14 +9,14 @@ macro_rules! global_meter { static $name: once_cell::sync::Lazy<$crate::opentelemetry::metrics::Meter> = once_cell::sync::Lazy::new(|| $crate::opentelemetry::global::meter(stringify!($name))); }; - ($name:ident, $description:literal) => { - static $name: once_cell::sync::Lazy<$crate::opentelemetry::metrics::Meter> = - once_cell::sync::Lazy::new(|| $crate::opentelemetry::global::meter($description)); + ($meter:ident, $name:literal) => { + static $meter: once_cell::sync::Lazy<$crate::opentelemetry::metrics::Meter> = + once_cell::sync::Lazy::new(|| $crate::opentelemetry::global::meter(stringify!($name))); }; } /// Create a [`Counter`][Counter] metric with the specified name and an optional description, -/// associated with the specified meter. Note that the meter must be to a valid [`Meter`][Meter]. +/// associated with the specified meter. Note that the meter must be a valid [`Meter`][Meter]. /// /// [Counter]: opentelemetry::metrics::Counter /// [Meter]: opentelemetry::metrics::Meter @@ -36,36 +25,54 @@ macro_rules! counter_metric { ($name:ident, $meter:ident) => { pub(crate) static $name: once_cell::sync::Lazy< $crate::opentelemetry::metrics::Counter, - > = once_cell::sync::Lazy::new(|| $meter.u64_counter(stringify!($name)).init()); + > = once_cell::sync::Lazy::new(|| $meter.u64_counter(stringify!($name)).build()); }; ($name:ident, $meter:ident, description:literal) => { + #[doc = $description] pub(crate) static $name: once_cell::sync::Lazy< $crate::opentelemetry::metrics::Counter, - > = once_cell::sync::Lazy::new(|| $meter.u64_counter($description).init()); + > = once_cell::sync::Lazy::new(|| { + $meter + .u64_counter(stringify!($name)) + .with_description($description) + .build() + }); }; } -/// Create a [`Histogram`][Histogram] metric with the specified name and an optional description, -/// associated with the specified meter. Note that the meter must be to a valid [`Meter`][Meter]. +/// Create a [`Histogram`][Histogram] f64 metric with the specified name and an optional description, +/// associated with the specified meter. Note that the meter must be a valid [`Meter`][Meter]. /// /// [Histogram]: opentelemetry::metrics::Histogram /// [Meter]: opentelemetry::metrics::Meter #[macro_export] -macro_rules! histogram_metric { +macro_rules! histogram_metric_f64 { ($name:ident, $meter:ident) => { pub(crate) static $name: once_cell::sync::Lazy< $crate::opentelemetry::metrics::Histogram, - > = once_cell::sync::Lazy::new(|| $meter.f64_histogram(stringify!($name)).init()); + > = once_cell::sync::Lazy::new(|| { + $meter + .f64_histogram(stringify!($name)) + .with_boundaries($crate::metrics::f64_histogram_buckets()) + .build() + }); }; ($name:ident, $meter:ident, $description:literal) => { + #[doc = $description] pub(crate) static $name: once_cell::sync::Lazy< $crate::opentelemetry::metrics::Histogram, - > = once_cell::sync::Lazy::new(|| $meter.f64_histogram($description).init()); + > = once_cell::sync::Lazy::new(|| { + $meter + .f64_histogram(stringify!($name)) + .with_description($description) + .with_boundaries($crate::metrics::f64_histogram_buckets()) + .build() + }); }; } /// Create a [`Histogram`][Histogram] u64 metric with the specified name and an optional description, -/// associated with the specified meter. Note that the meter must be to a valid [`Meter`][Meter]. +/// associated with the specified meter. Note that the meter must be a valid [`Meter`][Meter]. /// /// [Histogram]: opentelemetry::metrics::Histogram /// [Meter]: opentelemetry::metrics::Meter @@ -74,64 +81,72 @@ macro_rules! histogram_metric_u64 { ($name:ident, $meter:ident) => { pub(crate) static $name: once_cell::sync::Lazy< $crate::opentelemetry::metrics::Histogram, - > = once_cell::sync::Lazy::new(|| $meter.u64_histogram(stringify!($name)).init()); + > = once_cell::sync::Lazy::new(|| { + $meter + .u64_histogram(stringify!($name)) + .with_boundaries($crate::metrics::f64_histogram_buckets()) + .build() + }); }; ($name:ident, $meter:ident, $description:literal) => { + #[doc = $description] pub(crate) static $name: once_cell::sync::Lazy< $crate::opentelemetry::metrics::Histogram, - > = once_cell::sync::Lazy::new(|| $meter.u64_histogram($description).init()); + > = once_cell::sync::Lazy::new(|| { + $meter + .u64_histogram(stringify!($name)) + .with_description($description) + .with_boundaries($crate::metrics::f64_histogram_buckets()) + .build() + }); }; } -/// Create a [`Histogram`][Histogram] i64 metric with the specified name and an optional description, -/// associated with the specified meter. Note that the meter must be to a valid [`Meter`][Meter]. +/// Create a [`Gauge`][Gauge] metric with the specified name and an optional description, +/// associated with the specified meter. Note that the meter must be a valid [`Meter`][Meter]. /// -/// [Histogram]: opentelemetry::metrics::Histogram +/// [Gauge]: opentelemetry::metrics::Gauge /// [Meter]: opentelemetry::metrics::Meter #[macro_export] -macro_rules! histogram_metric_i64 { +macro_rules! gauge_metric { ($name:ident, $meter:ident) => { - pub(crate) static $name: once_cell::sync::Lazy< - $crate::opentelemetry::metrics::Histogram, - > = once_cell::sync::Lazy::new(|| $meter.i64_histogram(stringify!($name)).init()); + pub(crate) static $name: once_cell::sync::Lazy<$crate::opentelemetry::metrics::Gauge> = + once_cell::sync::Lazy::new(|| $meter.u64_gauge(stringify!($name)).build()); }; - ($name:ident, $meter:ident, $description:literal) => { - pub(crate) static $name: once_cell::sync::Lazy< - $crate::opentelemetry::metrics::Histogram, - > = once_cell::sync::Lazy::new(|| $meter.i64_histogram($description).init()); + ($name:ident, $meter:ident, description:literal) => { + #[doc = $description] + pub(crate) static $name: once_cell::sync::Lazy<$crate::opentelemetry::metrics::Gauge> = + once_cell::sync::Lazy::new(|| { + $meter + .u64_gauge(stringify!($name)) + .with_description($description) + .build() + }); }; } -/// Create a [`ObservableGauge`][ObservableGauge] metric with the specified name and an optional description, -/// associated with the specified meter. Note that the meter must be to a valid [`Meter`][Meter]. -/// -/// [ObservableGauge]: opentelemetry::metrics::ObservableGauge -/// [Meter]: opentelemetry::metrics::Meter +/// Create attributes to associate with a metric from key-value pairs. #[macro_export] -macro_rules! gauge_metric { - ($name:ident, $meter:ident) => { - pub(crate) static $name: once_cell::sync::Lazy< - $crate::opentelemetry::metrics::ObservableGauge, - > = once_cell::sync::Lazy::new(|| $meter.u64_observable_gauge(stringify!($name)).init()); - }; - ($name:ident, $meter:ident, description:literal) => { - pub(crate) static $name: once_cell::sync::Lazy< - $crate::opentelemetry::metrics::ObservableGauge, - > = once_cell::sync::Lazy::new(|| $meter.u64_observable_gauge($description).init()); +macro_rules! metric_attributes { + ($(($key:expr, $value:expr $(,)?)),+ $(,)?) => { + &[$($crate::opentelemetry::KeyValue::new($key, $value)),+] }; } -pub use helpers::add_attributes; +pub use helpers::f64_histogram_buckets; mod helpers { - pub fn add_attributes(attributes: U) -> Vec - where - T: Into, - U: IntoIterator, - { - attributes - .into_iter() - .map(|(key, value)| opentelemetry::KeyValue::new(key, value)) - .collect::>() + /// Returns the buckets to be used for a f64 histogram + #[inline(always)] + pub fn f64_histogram_buckets() -> Vec { + let mut init = 0.01; + let mut buckets: [f64; 15] = [0.0; 15]; + + for bucket in &mut buckets { + init *= 2.0; + *bucket = init; + } + + Vec::from(buckets) } } diff --git a/crates/scheduler/src/consumer.rs b/crates/scheduler/src/consumer.rs index 846f1137b129..99b9df524ae0 100644 --- a/crates/scheduler/src/consumer.rs +++ b/crates/scheduler/src/consumer.rs @@ -165,7 +165,7 @@ pub async fn consumer_operations( pt_utils::add_histogram_metrics(&pickup_time, task, &stream_name); - metrics::TASK_CONSUMED.add(&metrics::CONTEXT, 1, &[]); + metrics::TASK_CONSUMED.add(1, &[]); handler.push(tokio::task::spawn(start_workflow( state.clone(), @@ -244,7 +244,7 @@ where .inspect_err(|error| { logger::error!(?error, "Failed to trigger workflow"); }); - metrics::TASK_PROCESSED.add(&metrics::CONTEXT, 1, &[]); + metrics::TASK_PROCESSED.add(1, &[]); res } diff --git a/crates/scheduler/src/db/process_tracker.rs b/crates/scheduler/src/db/process_tracker.rs index c73b53b608c2..1b23ff1b5579 100644 --- a/crates/scheduler/src/db/process_tracker.rs +++ b/crates/scheduler/src/db/process_tracker.rs @@ -149,7 +149,7 @@ impl ProcessTrackerInterface for Store { this: storage::ProcessTracker, schedule_time: PrimitiveDateTime, ) -> CustomResult<(), errors::StorageError> { - metrics::TASK_RETRIED.add(&metrics::CONTEXT, 1, &[]); + metrics::TASK_RETRIED.add(1, &[]); let retry_count = this.retry_count + 1; self.update_process( this, @@ -177,7 +177,7 @@ impl ProcessTrackerInterface for Store { ) .await .attach_printable("Failed to update business status of process")?; - metrics::TASK_FINISHED.add(&metrics::CONTEXT, 1, &[]); + metrics::TASK_FINISHED.add(1, &[]); Ok(()) } diff --git a/crates/scheduler/src/metrics.rs b/crates/scheduler/src/metrics.rs index ca4fb9ec2424..27ac860d0794 100644 --- a/crates/scheduler/src/metrics.rs +++ b/crates/scheduler/src/metrics.rs @@ -1,9 +1,8 @@ -use router_env::{counter_metric, global_meter, histogram_metric, metrics_context}; +use router_env::{counter_metric, global_meter, histogram_metric_f64}; -metrics_context!(CONTEXT); global_meter!(PT_METER, "PROCESS_TRACKER"); -histogram_metric!(CONSUMER_STATS, PT_METER, "CONSUMER_OPS"); +histogram_metric_f64!(CONSUMER_OPS, PT_METER); counter_metric!(PAYMENT_COUNT, PT_METER); // No. of payments created counter_metric!(TASKS_PICKED_COUNT, PT_METER); // Tasks picked by diff --git a/crates/scheduler/src/producer.rs b/crates/scheduler/src/producer.rs index b91434fcbb04..3d28ec91fab8 100644 --- a/crates/scheduler/src/producer.rs +++ b/crates/scheduler/src/producer.rs @@ -175,6 +175,6 @@ pub async fn fetch_producer_tasks( // Safety: Assuming we won't deal with more than `u64::MAX` tasks at once #[allow(clippy::as_conversions)] - metrics::TASKS_PICKED_COUNT.add(&metrics::CONTEXT, new_tasks.len() as u64, &[]); + metrics::TASKS_PICKED_COUNT.add(new_tasks.len() as u64, &[]); Ok(new_tasks) } diff --git a/crates/scheduler/src/utils.rs b/crates/scheduler/src/utils.rs index e4b636ac5f11..89328479537e 100644 --- a/crates/scheduler/src/utils.rs +++ b/crates/scheduler/src/utils.rs @@ -5,7 +5,7 @@ use diesel_models::enums::{self, ProcessTrackerStatus}; pub use diesel_models::process_tracker as storage; use error_stack::{report, ResultExt}; use redis_interface::{RedisConnectionPool, RedisEntryId}; -use router_env::{instrument, opentelemetry, tracing}; +use router_env::{instrument, tracing}; use uuid::Uuid; use super::{ @@ -29,7 +29,7 @@ where let batches = divide(tasks, settings); // Safety: Assuming we won't deal with more than `u64::MAX` batches at once #[allow(clippy::as_conversions)] - metrics::BATCHES_CREATED.add(&metrics::CONTEXT, batches.len() as u64, &[]); // Metrics + metrics::BATCHES_CREATED.add(batches.len() as u64, &[]); // Metrics for batch in batches { let result = update_status_and_append(state, flow, batch).await; match result { @@ -209,7 +209,7 @@ pub async fn get_batches( } }; - metrics::BATCHES_CONSUMED.add(&metrics::CONTEXT, 1, &[]); + metrics::BATCHES_CONSUMED.add(1, &[]); let (batches, entry_ids): (Vec>, Vec>) = response.into_values().map(|entries| { entries.into_iter().try_fold( @@ -290,13 +290,9 @@ pub fn add_histogram_metrics( let pickup_schedule_delta = (*pickup_time - *schedule_time).as_seconds_f64(); logger::error!("Time delta for scheduled tasks: {pickup_schedule_delta} seconds"); let runner_name = runner.clone(); - metrics::CONSUMER_STATS.record( - &metrics::CONTEXT, + metrics::CONSUMER_OPS.record( pickup_schedule_delta, - &[opentelemetry::KeyValue::new( - stream_name.to_owned(), - runner_name, - )], + router_env::metric_attributes!((stream_name.to_owned(), runner_name)), ); }; } diff --git a/crates/storage_impl/src/lib.rs b/crates/storage_impl/src/lib.rs index 9b306ec8b077..1d48606bf006 100644 --- a/crates/storage_impl/src/lib.rs +++ b/crates/storage_impl/src/lib.rs @@ -262,9 +262,9 @@ impl KVRouterStore { .change_context(RedisError::JsonSerializationFailed)?, ) .await - .map(|_| metrics::KV_PUSHED_TO_DRAINER.add(&metrics::CONTEXT, 1, &[])) + .map(|_| metrics::KV_PUSHED_TO_DRAINER.add(1, &[])) .inspect_err(|error| { - metrics::KV_FAILED_TO_PUSH_TO_DRAINER.add(&metrics::CONTEXT, 1, &[]); + metrics::KV_FAILED_TO_PUSH_TO_DRAINER.add(1, &[]); logger::error!(?error, "Failed to add entry in drainer stream"); }) .change_context(RedisError::StreamAppendFailed) diff --git a/crates/storage_impl/src/metrics.rs b/crates/storage_impl/src/metrics.rs index cb7a6b216e47..b0c0c70af0a5 100644 --- a/crates/storage_impl/src/metrics.rs +++ b/crates/storage_impl/src/metrics.rs @@ -1,6 +1,5 @@ -use router_env::{counter_metric, gauge_metric, global_meter, metrics_context}; +use router_env::{counter_metric, gauge_metric, global_meter}; -metrics_context!(CONTEXT); global_meter!(GLOBAL_METER, "ROUTER_API"); counter_metric!(KV_MISS, GLOBAL_METER); // No. of KV misses diff --git a/crates/storage_impl/src/redis/cache.rs b/crates/storage_impl/src/redis/cache.rs index fff5435fc74d..93255fac9144 100644 --- a/crates/storage_impl/src/redis/cache.rs +++ b/crates/storage_impl/src/redis/cache.rs @@ -9,10 +9,7 @@ use error_stack::{Report, ResultExt}; use moka::future::Cache as MokaCache; use once_cell::sync::Lazy; use redis_interface::{errors::RedisError, RedisConnectionPool, RedisValue}; -use router_env::{ - metrics::add_attributes, - tracing::{self, instrument}, -}; +use router_env::tracing::{self, instrument}; use crate::{ errors::StorageError, @@ -193,12 +190,11 @@ impl Cache { // Record the metrics of manual invalidation of cache entry by the application let eviction_listener = move |_, _, cause| { metrics::IN_MEMORY_CACHE_EVICTION_COUNT.add( - &metrics::CONTEXT, 1, - &add_attributes([ + router_env::metric_attributes!( ("cache_type", name.to_owned()), ("removal_cause", format!("{:?}", cause)), - ]), + ), ); }; let mut cache_builder = MokaCache::builder() @@ -225,17 +221,11 @@ impl Cache { // Add cache hit and cache miss metrics if val.is_some() { - metrics::IN_MEMORY_CACHE_HIT.add( - &metrics::CONTEXT, - 1, - &add_attributes([("cache_type", self.name)]), - ); + metrics::IN_MEMORY_CACHE_HIT + .add(1, router_env::metric_attributes!(("cache_type", self.name))); } else { - metrics::IN_MEMORY_CACHE_MISS.add( - &metrics::CONTEXT, - 1, - &add_attributes([("cache_type", self.name)]), - ); + metrics::IN_MEMORY_CACHE_MISS + .add(1, router_env::metric_attributes!(("cache_type", self.name))); } let val = (*val?).as_any().downcast_ref::().cloned(); @@ -269,10 +259,9 @@ impl Cache { pub async fn record_entry_count_metric(&self) { self.run_pending_tasks().await; - metrics::IN_MEMORY_CACHE_ENTRY_COUNT.observe( - &metrics::CONTEXT, + metrics::IN_MEMORY_CACHE_ENTRY_COUNT.record( self.get_entry_count(), - &add_attributes([("cache_type", self.name)]), + router_env::metric_attributes!(("cache_type", self.name)), ); } } diff --git a/crates/storage_impl/src/redis/kv_store.rs b/crates/storage_impl/src/redis/kv_store.rs index 83d8de9c30ac..9203a14ae21c 100644 --- a/crates/storage_impl/src/redis/kv_store.rs +++ b/crates/storage_impl/src/redis/kv_store.rs @@ -257,19 +257,16 @@ where } }; + let attributes = router_env::metric_attributes!(("operation", operation.clone())); result .await .inspect(|_| { logger::debug!(kv_operation= %operation, status="success"); - let keyvalue = router_env::opentelemetry::KeyValue::new("operation", operation.clone()); - - metrics::KV_OPERATION_SUCCESSFUL.add(&metrics::CONTEXT, 1, &[keyvalue]); + metrics::KV_OPERATION_SUCCESSFUL.add(1, attributes); }) .inspect_err(|err| { logger::error!(kv_operation = %operation, status="error", error = ?err); - let keyvalue = router_env::opentelemetry::KeyValue::new("operation", operation); - - metrics::KV_OPERATION_FAILED.add(&metrics::CONTEXT, 1, &[keyvalue]); + metrics::KV_OPERATION_FAILED.add(1, attributes); }) } @@ -320,7 +317,7 @@ where .await { Ok(_) => { - metrics::KV_SOFT_KILL_ACTIVE_UPDATE.add(&metrics::CONTEXT, 1, &[]); + metrics::KV_SOFT_KILL_ACTIVE_UPDATE.add(1, &[]); MerchantStorageScheme::RedisKv } Err(_) => MerchantStorageScheme::PostgresOnly, diff --git a/crates/storage_impl/src/utils.rs b/crates/storage_impl/src/utils.rs index b634f41a98f1..01e0e8cbc141 100644 --- a/crates/storage_impl/src/utils.rs +++ b/crates/storage_impl/src/utils.rs @@ -59,7 +59,7 @@ where Ok(output) => Ok(output), Err(redis_error) => match redis_error.current_context() { redis_interface::errors::RedisError::NotFound => { - metrics::KV_MISS.add(&metrics::CONTEXT, 1, &[]); + metrics::KV_MISS.add(1, &[]); database_call_closure().await } // Keeping the key empty here since the error would never go here. From 1aa4ad60e2326cbdc5c81479cf3420c3f3e1d8ee Mon Sep 17 00:00:00 2001 From: Prajjwal Kumar Date: Tue, 10 Dec 2024 16:38:34 +0530 Subject: [PATCH 07/51] refactor(constraint_graph): add setup_future_usage for mandate check in payments (#6744) --- .../router/src/core/payment_methods/cards.rs | 15 +++++++++++- .../router/src/core/payment_methods/utils.rs | 24 +++++++++++-------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 259f77c81a30..135759611082 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -4558,6 +4558,12 @@ pub async fn filter_payment_methods( if payment_attempt .and_then(|attempt| attempt.mandate_details.as_ref()) .is_some() + || payment_intent + .and_then(|intent| intent.setup_future_usage) + .map(|future_usage| { + future_usage == common_enums::FutureUsage::OffSession + }) + .unwrap_or(false) { context_values.push(dir::DirValue::PaymentType( euclid::enums::PaymentType::NewMandate, @@ -4576,7 +4582,14 @@ pub async fn filter_payment_methods( payment_attempt .map(|attempt| { - attempt.mandate_data.is_none() && attempt.mandate_details.is_none() + attempt.mandate_data.is_none() + && attempt.mandate_details.is_none() + && payment_intent + .and_then(|intent| intent.setup_future_usage) + .map(|future_usage| { + future_usage == common_enums::FutureUsage::OnSession + }) + .unwrap_or(false) }) .and_then(|res| { res.then(|| { diff --git a/crates/router/src/core/payment_methods/utils.rs b/crates/router/src/core/payment_methods/utils.rs index 816807fe0149..d7e83cb5bf22 100644 --- a/crates/router/src/core/payment_methods/utils.rs +++ b/crates/router/src/core/payment_methods/utils.rs @@ -429,16 +429,20 @@ fn construct_supported_connectors_for_update_mandate_node( } } - Ok(Some( - builder - .make_any_aggregator( - &agg_nodes, - Some("any node for card and non card pm"), - None::<()>, - Some(domain_id), - ) - .map_err(KgraphError::GraphConstructionError)?, - )) + if !agg_nodes.is_empty() { + Ok(Some( + builder + .make_any_aggregator( + &agg_nodes, + Some("any node for card and non card pm"), + None::<()>, + Some(domain_id), + ) + .map_err(KgraphError::GraphConstructionError)?, + )) + } else { + Ok(None) + } } fn construct_supported_connectors_for_mandate_node( From 3df42333566b646e9ca93d612a78ea8d38298df4 Mon Sep 17 00:00:00 2001 From: Sandeep Kumar <83278309+tsdk02@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:38:34 +0530 Subject: [PATCH 08/51] feat(analytics): add support for multiple emails as input to forward reports (#6776) --- crates/api_models/src/analytics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/api_models/src/analytics.rs b/crates/api_models/src/analytics.rs index 806eb4b6e0e8..7f58c6b00d78 100644 --- a/crates/api_models/src/analytics.rs +++ b/crates/api_models/src/analytics.rs @@ -114,6 +114,7 @@ pub struct RefundDistributionBody { #[serde(rename_all = "camelCase")] pub struct ReportRequest { pub time_range: TimeRange, + pub emails: Option>>, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] From c620779bbd14a1102d4fff68cc36581935d87da7 Mon Sep 17 00:00:00 2001 From: ShivanshMathurJuspay <104988143+ShivanshMathurJuspay@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:48:50 +0530 Subject: [PATCH 09/51] refactor(events): Tenant config in API, Connector and Outgoing Web-hook events (#6777) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/hyperswitch_interfaces/src/events/connector_api_logs.rs | 3 +++ crates/router/src/core/webhooks/incoming.rs | 1 + crates/router/src/core/webhooks/incoming_v2.rs | 1 + crates/router/src/core/webhooks/outgoing.rs | 1 + crates/router/src/events/api_logs.rs | 3 +++ crates/router/src/events/outgoing_webhook_logs.rs | 3 +++ crates/router/src/services/api.rs | 2 ++ 7 files changed, 14 insertions(+) diff --git a/crates/hyperswitch_interfaces/src/events/connector_api_logs.rs b/crates/hyperswitch_interfaces/src/events/connector_api_logs.rs index 5edd8d68c32d..bf9eafe5aaff 100644 --- a/crates/hyperswitch_interfaces/src/events/connector_api_logs.rs +++ b/crates/hyperswitch_interfaces/src/events/connector_api_logs.rs @@ -9,6 +9,7 @@ use time::OffsetDateTime; /// struct ConnectorEvent #[derive(Debug, Serialize)] pub struct ConnectorEvent { + tenant_id: common_utils::id_type::TenantId, connector_name: String, flow: String, request: String, @@ -31,6 +32,7 @@ impl ConnectorEvent { /// fn new ConnectorEvent #[allow(clippy::too_many_arguments)] pub fn new( + tenant_id: common_utils::id_type::TenantId, connector_name: String, flow: &str, request: serde_json::Value, @@ -45,6 +47,7 @@ impl ConnectorEvent { status_code: u16, ) -> Self { Self { + tenant_id, connector_name, flow: flow .rsplit_once("::") diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index 4b9141c649e9..73d9cfdcaee6 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -99,6 +99,7 @@ pub async fn incoming_webhooks_wrapper( .attach_printable("Could not convert webhook effect to string")?; let api_event = ApiEvent::new( + state.tenant.tenant_id.clone(), Some(merchant_account.get_id().clone()), flow, &request_id, diff --git a/crates/router/src/core/webhooks/incoming_v2.rs b/crates/router/src/core/webhooks/incoming_v2.rs index d331e4d67f3d..139ae18c1717 100644 --- a/crates/router/src/core/webhooks/incoming_v2.rs +++ b/crates/router/src/core/webhooks/incoming_v2.rs @@ -91,6 +91,7 @@ pub async fn incoming_webhooks_wrapper( .attach_printable("Could not convert webhook effect to string")?; let api_event = ApiEvent::new( + state.tenant.tenant_id.clone(), Some(merchant_account.get_id().clone()), flow, &request_id, diff --git a/crates/router/src/core/webhooks/outgoing.rs b/crates/router/src/core/webhooks/outgoing.rs index 16d927be2682..4bb45327d875 100644 --- a/crates/router/src/core/webhooks/outgoing.rs +++ b/crates/router/src/core/webhooks/outgoing.rs @@ -499,6 +499,7 @@ async fn raise_webhooks_analytics_event( }); let webhook_event = OutgoingWebhookEvent::new( + state.tenant.tenant_id.clone(), merchant_id, event_id, event.event_type, diff --git a/crates/router/src/events/api_logs.rs b/crates/router/src/events/api_logs.rs index 76cbcb958c87..419164810c3b 100644 --- a/crates/router/src/events/api_logs.rs +++ b/crates/router/src/events/api_logs.rs @@ -24,6 +24,7 @@ use crate::{ #[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[serde(rename_all = "snake_case")] pub struct ApiEvent { + tenant_id: common_utils::id_type::TenantId, merchant_id: Option, api_flow: String, created_at_timestamp: i128, @@ -47,6 +48,7 @@ pub struct ApiEvent { impl ApiEvent { #[allow(clippy::too_many_arguments)] pub fn new( + tenant_id: common_utils::id_type::TenantId, merchant_id: Option, api_flow: &impl FlowMetric, request_id: &RequestId, @@ -62,6 +64,7 @@ impl ApiEvent { http_method: &http::Method, ) -> Self { Self { + tenant_id, merchant_id, api_flow: api_flow.to_string(), created_at_timestamp: OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000_000, diff --git a/crates/router/src/events/outgoing_webhook_logs.rs b/crates/router/src/events/outgoing_webhook_logs.rs index 64126ec76d98..b56c473920dc 100644 --- a/crates/router/src/events/outgoing_webhook_logs.rs +++ b/crates/router/src/events/outgoing_webhook_logs.rs @@ -10,6 +10,7 @@ use crate::services::kafka::KafkaMessage; #[derive(Clone, Debug, PartialEq, Serialize)] #[serde(rename_all = "snake_case")] pub struct OutgoingWebhookEvent { + tenant_id: common_utils::id_type::TenantId, merchant_id: common_utils::id_type::MerchantId, event_id: String, event_type: OutgoingWebhookEventType, @@ -147,6 +148,7 @@ impl OutgoingWebhookEventMetric for OutgoingWebhookContent { impl OutgoingWebhookEvent { #[allow(clippy::too_many_arguments)] pub fn new( + tenant_id: common_utils::id_type::TenantId, merchant_id: common_utils::id_type::MerchantId, event_id: String, event_type: OutgoingWebhookEventType, @@ -157,6 +159,7 @@ impl OutgoingWebhookEvent { delivery_attempt: Option, ) -> Self { Self { + tenant_id, merchant_id, event_id, event_type, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index a4c1cac0ac43..cfff235856b3 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -228,6 +228,7 @@ where }) .unwrap_or_default(); let mut connector_event = ConnectorEvent::new( + state.tenant.tenant_id.clone(), req.connector.clone(), std::any::type_name::(), masked_request_body, @@ -851,6 +852,7 @@ where }; let api_event = ApiEvent::new( + tenant_id, Some(merchant_id.clone()), flow, &request_id, From f96a87d08ca003411d63dcd9ef4dda6439d20e07 Mon Sep 17 00:00:00 2001 From: Riddhiagrawal001 <50551695+Riddhiagrawal001@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:49:17 +0530 Subject: [PATCH 10/51] refactor(users): remove lineage checks in roles get operations (#6701) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/diesel_models/src/query/role.rs | 36 ++++++++++-- crates/diesel_models/src/user_role.rs | 11 ++-- crates/router/src/analytics.rs | 30 ++++------ crates/router/src/core/user.rs | 48 +++++----------- crates/router/src/core/user_role.rs | 26 ++++----- crates/router/src/core/user_role/role.rs | 34 +++++------ crates/router/src/db/kafka_store.rs | 16 +++++- crates/router/src/db/role.rs | 57 +++++++++++++++++-- crates/router/src/services/authorization.rs | 6 +- .../src/services/authorization/roles.rs | 8 +-- .../src/types/domain/user/decision_manager.rs | 6 +- crates/router/src/utils/user.rs | 11 +--- crates/router/src/utils/user_role.rs | 36 ++++-------- .../down.sql | 2 + .../up.sql | 10 ++++ 15 files changed, 188 insertions(+), 149 deletions(-) create mode 100644 migrations/2024-12-02-110129_update-user-role-entity-type/down.sql create mode 100644 migrations/2024-12-02-110129_update-user-role-entity-type/up.sql diff --git a/crates/diesel_models/src/query/role.rs b/crates/diesel_models/src/query/role.rs index 065a5b6e114e..6f6a1404ee2c 100644 --- a/crates/diesel_models/src/query/role.rs +++ b/crates/diesel_models/src/query/role.rs @@ -26,6 +26,7 @@ impl Role { .await } + // TODO: Remove once find_by_role_id_in_lineage is stable pub async fn find_by_role_id_in_merchant_scope( conn: &PgPooledConn, role_id: &str, @@ -43,7 +44,27 @@ impl Role { .await } - pub async fn find_by_role_id_in_org_scope( + pub async fn find_by_role_id_in_lineage( + conn: &PgPooledConn, + role_id: &str, + merchant_id: &id_type::MerchantId, + org_id: &id_type::OrganizationId, + ) -> StorageResult { + generics::generic_find_one::<::Table, _, _>( + conn, + dsl::role_id + .eq(role_id.to_owned()) + .and(dsl::org_id.eq(org_id.to_owned())) + .and( + dsl::scope.eq(RoleScope::Organization).or(dsl::merchant_id + .eq(merchant_id.to_owned()) + .and(dsl::scope.eq(RoleScope::Merchant))), + ), + ) + .await + } + + pub async fn find_by_role_id_and_org_id( conn: &PgPooledConn, role_id: &str, org_id: &id_type::OrganizationId, @@ -88,9 +109,11 @@ impl Role { merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, ) -> StorageResult> { - let predicate = dsl::merchant_id.eq(merchant_id.to_owned()).or(dsl::org_id - .eq(org_id.to_owned()) - .and(dsl::scope.eq(RoleScope::Organization))); + let predicate = dsl::org_id.eq(org_id.to_owned()).and( + dsl::scope.eq(RoleScope::Organization).or(dsl::merchant_id + .eq(merchant_id.to_owned()) + .and(dsl::scope.eq(RoleScope::Merchant))), + ); generics::generic_filter::<::Table, _, _, _>( conn, @@ -115,9 +138,10 @@ impl Role { if let Some(merchant_id) = merchant_id { query = query.filter( - dsl::merchant_id + (dsl::merchant_id .eq(merchant_id) - .or(dsl::scope.eq(RoleScope::Organization)), + .and(dsl::scope.eq(RoleScope::Merchant))) + .or(dsl::scope.eq(RoleScope::Organization)), ); } diff --git a/crates/diesel_models/src/user_role.rs b/crates/diesel_models/src/user_role.rs index 04f3264b45e3..08449685b291 100644 --- a/crates/diesel_models/src/user_role.rs +++ b/crates/diesel_models/src/user_role.rs @@ -29,16 +29,19 @@ pub struct UserRole { impl UserRole { pub fn get_entity_id_and_type(&self) -> Option<(String, EntityType)> { - match (self.version, self.role_id.as_str()) { - (enums::UserRoleVersion::V1, consts::ROLE_ID_ORGANIZATION_ADMIN) => { + match (self.version, self.entity_type, self.role_id.as_str()) { + (enums::UserRoleVersion::V1, None, consts::ROLE_ID_ORGANIZATION_ADMIN) => { let org_id = self.org_id.clone()?.get_string_repr().to_string(); Some((org_id, EntityType::Organization)) } - (enums::UserRoleVersion::V1, _) => { + (enums::UserRoleVersion::V1, None, _) => { let merchant_id = self.merchant_id.clone()?.get_string_repr().to_string(); Some((merchant_id, EntityType::Merchant)) } - (enums::UserRoleVersion::V2, _) => self.entity_id.clone().zip(self.entity_type), + (enums::UserRoleVersion::V1, Some(_), _) => { + self.entity_id.clone().zip(self.entity_type) + } + (enums::UserRoleVersion::V2, _, _) => self.entity_id.clone().zip(self.entity_type), } } } diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index 752c3a52284a..ff2744b824ed 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -1847,15 +1847,10 @@ pub mod routes { json_payload.into_inner(), |state, auth: UserFromToken, req, _| async move { let role_id = auth.role_id; - let role_info = RoleInfo::from_role_id_in_merchant_scope( - &state, - &role_id, - &auth.merchant_id, - &auth.org_id, - ) - .await - .change_context(UserErrors::InternalServerError) - .change_context(OpenSearchError::UnknownError)?; + let role_info = RoleInfo::from_role_id_and_org_id(&state, &role_id, &auth.org_id) + .await + .change_context(UserErrors::InternalServerError) + .change_context(OpenSearchError::UnknownError)?; let permission_groups = role_info.get_permission_groups(); if !permission_groups.contains(&common_enums::PermissionGroup::OperationsView) { return Err(OpenSearchError::AccessForbiddenError)?; @@ -1887,7 +1882,7 @@ pub mod routes { let role_id = user_role.role_id.clone(); let org_id = user_role.org_id.clone().unwrap_or_default(); async move { - RoleInfo::from_role_id_in_org_scope(&state, &role_id, &org_id) + RoleInfo::from_role_id_and_org_id(&state, &role_id, &org_id) .await .change_context(UserErrors::InternalServerError) .change_context(OpenSearchError::UnknownError) @@ -1974,15 +1969,10 @@ pub mod routes { indexed_req, |state, auth: UserFromToken, req, _| async move { let role_id = auth.role_id; - let role_info = RoleInfo::from_role_id_in_merchant_scope( - &state, - &role_id, - &auth.merchant_id, - &auth.org_id, - ) - .await - .change_context(UserErrors::InternalServerError) - .change_context(OpenSearchError::UnknownError)?; + let role_info = RoleInfo::from_role_id_and_org_id(&state, &role_id, &auth.org_id) + .await + .change_context(UserErrors::InternalServerError) + .change_context(OpenSearchError::UnknownError)?; let permission_groups = role_info.get_permission_groups(); if !permission_groups.contains(&common_enums::PermissionGroup::OperationsView) { return Err(OpenSearchError::AccessForbiddenError)?; @@ -2013,7 +2003,7 @@ pub mod routes { let role_id = user_role.role_id.clone(); let org_id = user_role.org_id.clone().unwrap_or_default(); async move { - RoleInfo::from_role_id_in_org_scope(&state, &role_id, &org_id) + RoleInfo::from_role_id_and_org_id(&state, &role_id, &org_id) .await .change_context(UserErrors::InternalServerError) .change_context(OpenSearchError::UnknownError) diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index f99c44cf2980..629476b2591e 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -104,10 +104,9 @@ pub async fn get_user_details( ) -> UserResponse { let user = user_from_token.get_user_from_db(&state).await?; let verification_days_left = utils::user::get_verification_days_left(&state, &user)?; - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -553,7 +552,7 @@ async fn handle_invitation( .into()); } - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_in_lineage( state, &request.role_id, &user_from_token.merchant_id, @@ -1371,10 +1370,9 @@ pub async fn list_user_roles_details( .await .to_not_found_response(UserErrors::InvalidRoleOperation)?; - let requestor_role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let requestor_role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -1526,7 +1524,7 @@ pub async fn list_user_roles_details( .collect::>() .into_iter() .map(|role_id| async { - let role_info = roles::RoleInfo::from_role_id_in_org_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &role_id, &user_from_token.org_id, @@ -2533,10 +2531,9 @@ pub async fn list_orgs_for_user( state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse> { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -2611,10 +2608,9 @@ pub async fn list_merchants_for_user_in_org( state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse> { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -2687,10 +2683,9 @@ pub async fn list_profiles_for_user_in_org_and_merchant_account( state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse> { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -2780,10 +2775,9 @@ pub async fn switch_org_for_user( .into()); } - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -2876,13 +2870,8 @@ pub async fn switch_org_for_user( ) .await?; - utils::user_role::set_role_permissions_in_cache_by_role_id_merchant_id_org_id( - &state, - &role_id, - &merchant_id, - &request.org_id, - ) - .await; + utils::user_role::set_role_info_in_cache_by_role_id_org_id(&state, &role_id, &request.org_id) + .await; let response = user_api::TokenResponse { token: token.clone(), @@ -2905,10 +2894,9 @@ pub async fn switch_merchant_for_user_in_org( } let key_manager_state = &(&state).into(); - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -3065,13 +3053,7 @@ pub async fn switch_merchant_for_user_in_org( ) .await?; - utils::user_role::set_role_permissions_in_cache_by_role_id_merchant_id_org_id( - &state, - &role_id, - &merchant_id, - &org_id, - ) - .await; + utils::user_role::set_role_info_in_cache_by_role_id_org_id(&state, &role_id, &org_id).await; let response = user_api::TokenResponse { token: token.clone(), @@ -3094,10 +3076,9 @@ pub async fn switch_profile_for_user_in_org_and_merchant( } let key_manager_state = &(&state).into(); - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -3175,10 +3156,9 @@ pub async fn switch_profile_for_user_in_org_and_merchant( ) .await?; - utils::user_role::set_role_permissions_in_cache_by_role_id_merchant_id_org_id( + utils::user_role::set_role_info_in_cache_by_role_id_org_id( &state, &role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await; diff --git a/crates/router/src/core/user_role.rs b/crates/router/src/core/user_role.rs index 31ec665b2ab2..d8fdff0e6233 100644 --- a/crates/router/src/core/user_role.rs +++ b/crates/router/src/core/user_role.rs @@ -83,10 +83,9 @@ pub async fn get_parent_group_info( state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse> { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -119,7 +118,7 @@ pub async fn update_user_role( req: user_role_api::UpdateUserRoleRequest, _req_state: ReqState, ) -> UserResponse<()> { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_in_lineage( &state, &req.role_id, &user_from_token.merchant_id, @@ -144,10 +143,9 @@ pub async fn update_user_role( .attach_printable("User Changing their own role"); } - let updator_role = roles::RoleInfo::from_role_id_in_merchant_scope( + let updator_role = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -181,10 +179,9 @@ pub async fn update_user_role( }; if let Some(user_role) = v2_user_role_to_be_updated { - let role_to_be_updated = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_to_be_updated = roles::RoleInfo::from_role_id_and_org_id( &state, &user_role.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -262,10 +259,9 @@ pub async fn update_user_role( }; if let Some(user_role) = v1_user_role_to_be_updated { - let role_to_be_updated = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_to_be_updated = roles::RoleInfo::from_role_id_and_org_id( &state, &user_role.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -489,10 +485,9 @@ pub async fn delete_user_role( .attach_printable("User deleting himself"); } - let deletion_requestor_role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let deletion_requestor_role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -527,7 +522,7 @@ pub async fn delete_user_role( }; if let Some(role_to_be_deleted) = user_role_v2 { - let target_role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let target_role_info = roles::RoleInfo::from_role_id_in_lineage( &state, &role_to_be_deleted.role_id, &user_from_token.merchant_id, @@ -597,7 +592,7 @@ pub async fn delete_user_role( }; if let Some(role_to_be_deleted) = user_role_v1 { - let target_role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let target_role_info = roles::RoleInfo::from_role_id_in_lineage( &state, &role_to_be_deleted.role_id, &user_from_token.merchant_id, @@ -685,10 +680,9 @@ pub async fn list_users_in_lineage( user_from_token: auth::UserFromToken, request: user_role_api::ListUsersInEntityRequest, ) -> UserResponse> { - let requestor_role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let requestor_role_info = roles::RoleInfo::from_role_id_and_org_id( &state, &user_from_token.role_id, - &user_from_token.merchant_id, &user_from_token.org_id, ) .await @@ -783,7 +777,7 @@ pub async fn list_users_in_lineage( let role_info_map = futures::future::try_join_all(user_roles_set.iter().map(|user_role| async { - roles::RoleInfo::from_role_id_in_org_scope( + roles::RoleInfo::from_role_id_and_org_id( &state, &user_role.role_id, &user_from_token.org_id, diff --git a/crates/router/src/core/user_role/role.rs b/crates/router/src/core/user_role/role.rs index 9f251f55bdf0..714bf9fed3cc 100644 --- a/crates/router/src/core/user_role/role.rs +++ b/crates/router/src/core/user_role/role.rs @@ -76,8 +76,10 @@ pub async fn create_role( ) .await?; + let user_role_info = user_from_token.get_role_info_from_db(&state).await?; + if matches!(req.role_scope, RoleScope::Organization) - && user_from_token.role_id != common_utils::consts::ROLE_ID_ORGANIZATION_ADMIN + && user_role_info.get_entity_type() != EntityType::Organization { return Err(report!(UserErrors::InvalidRoleOperation)) .attach_printable("Non org admin user creating org level role"); @@ -116,14 +118,10 @@ pub async fn get_role_with_groups( user_from_token: UserFromToken, role: role_api::GetRoleRequest, ) -> UserResponse { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( - &state, - &role.role_id, - &user_from_token.merchant_id, - &user_from_token.org_id, - ) - .await - .to_not_found_response(UserErrors::InvalidRoleId)?; + let role_info = + roles::RoleInfo::from_role_id_and_org_id(&state, &role.role_id, &user_from_token.org_id) + .await + .to_not_found_response(UserErrors::InvalidRoleId)?; if role_info.is_internal() { return Err(UserErrors::InvalidRoleId.into()); @@ -144,14 +142,10 @@ pub async fn get_parent_info_for_role( user_from_token: UserFromToken, role: role_api::GetRoleRequest, ) -> UserResponse { - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( - &state, - &role.role_id, - &user_from_token.merchant_id, - &user_from_token.org_id, - ) - .await - .to_not_found_response(UserErrors::InvalidRoleId)?; + let role_info = + roles::RoleInfo::from_role_id_and_org_id(&state, &role.role_id, &user_from_token.org_id) + .await + .to_not_found_response(UserErrors::InvalidRoleId)?; if role_info.is_internal() { return Err(UserErrors::InvalidRoleId.into()); @@ -207,7 +201,7 @@ pub async fn update_role( utils::user_role::validate_role_groups(groups)?; } - let role_info = roles::RoleInfo::from_role_id_in_merchant_scope( + let role_info = roles::RoleInfo::from_role_id_in_lineage( &state, role_id, &user_from_token.merchant_id, @@ -216,8 +210,10 @@ pub async fn update_role( .await .to_not_found_response(UserErrors::InvalidRoleOperation)?; + let user_role_info = user_from_token.get_role_info_from_db(&state).await?; + if matches!(role_info.get_scope(), RoleScope::Organization) - && user_from_token.role_id != common_utils::consts::ROLE_ID_ORGANIZATION_ADMIN + && user_role_info.get_entity_type() != EntityType::Organization { return Err(report!(UserErrors::InvalidRoleOperation)) .attach_printable("Non org admin user changing org level role"); diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 47c9adafb718..2fd30a3610b5 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -3521,6 +3521,7 @@ impl RoleInterface for KafkaStore { self.diesel_store.find_role_by_role_id(role_id).await } + //TODO:Remove once find_by_role_id_in_lineage is stable async fn find_role_by_role_id_in_merchant_scope( &self, role_id: &str, @@ -3532,13 +3533,24 @@ impl RoleInterface for KafkaStore { .await } - async fn find_role_by_role_id_in_org_scope( + async fn find_role_by_role_id_in_lineage( + &self, + role_id: &str, + merchant_id: &id_type::MerchantId, + org_id: &id_type::OrganizationId, + ) -> CustomResult { + self.diesel_store + .find_role_by_role_id_in_lineage(role_id, merchant_id, org_id) + .await + } + + async fn find_by_role_id_and_org_id( &self, role_id: &str, org_id: &id_type::OrganizationId, ) -> CustomResult { self.diesel_store - .find_role_by_role_id_in_org_scope(role_id, org_id) + .find_by_role_id_and_org_id(role_id, org_id) .await } diff --git a/crates/router/src/db/role.rs b/crates/router/src/db/role.rs index d13508356e5a..877a4c540774 100644 --- a/crates/router/src/db/role.rs +++ b/crates/router/src/db/role.rs @@ -23,6 +23,7 @@ pub trait RoleInterface { role_id: &str, ) -> CustomResult; + //TODO:Remove once find_by_role_id_in_lineage is stable async fn find_role_by_role_id_in_merchant_scope( &self, role_id: &str, @@ -30,7 +31,14 @@ pub trait RoleInterface { org_id: &id_type::OrganizationId, ) -> CustomResult; - async fn find_role_by_role_id_in_org_scope( + async fn find_role_by_role_id_in_lineage( + &self, + role_id: &str, + merchant_id: &id_type::MerchantId, + org_id: &id_type::OrganizationId, + ) -> CustomResult; + + async fn find_by_role_id_and_org_id( &self, role_id: &str, org_id: &id_type::OrganizationId, @@ -86,6 +94,7 @@ impl RoleInterface for Store { .map_err(|error| report!(errors::StorageError::from(error))) } + //TODO:Remove once find_by_role_id_in_lineage is stable #[instrument(skip_all)] async fn find_role_by_role_id_in_merchant_scope( &self, @@ -100,13 +109,26 @@ impl RoleInterface for Store { } #[instrument(skip_all)] - async fn find_role_by_role_id_in_org_scope( + async fn find_role_by_role_id_in_lineage( &self, role_id: &str, + merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, ) -> CustomResult { let conn = connection::pg_connection_read(self).await?; - storage::Role::find_by_role_id_in_org_scope(&conn, role_id, org_id) + storage::Role::find_by_role_id_in_lineage(&conn, role_id, merchant_id, org_id) + .await + .map_err(|error| report!(errors::StorageError::from(error))) + } + + #[instrument(skip_all)] + async fn find_by_role_id_and_org_id( + &self, + role_id: &str, + org_id: &id_type::OrganizationId, + ) -> CustomResult { + let conn = connection::pg_connection_read(self).await?; + storage::Role::find_by_role_id_and_org_id(&conn, role_id, org_id) .await .map_err(|error| report!(errors::StorageError::from(error))) } @@ -217,6 +239,7 @@ impl RoleInterface for MockDb { ) } + // TODO: Remove once find_by_role_id_in_lineage is stable async fn find_role_by_role_id_in_merchant_scope( &self, role_id: &str, @@ -241,7 +264,33 @@ impl RoleInterface for MockDb { ) } - async fn find_role_by_role_id_in_org_scope( + async fn find_role_by_role_id_in_lineage( + &self, + role_id: &str, + merchant_id: &id_type::MerchantId, + org_id: &id_type::OrganizationId, + ) -> CustomResult { + let roles = self.roles.lock().await; + roles + .iter() + .find(|role| { + role.role_id == role_id + && role.org_id == *org_id + && ((role.scope == enums::RoleScope::Organization) + || (role.merchant_id == *merchant_id + && role.scope == enums::RoleScope::Merchant)) + }) + .cloned() + .ok_or( + errors::StorageError::ValueNotFound(format!( + "No role available in merchant scope for role_id = {role_id}, \ + merchant_id = {merchant_id:?} and org_id = {org_id:?}" + )) + .into(), + ) + } + + async fn find_by_role_id_and_org_id( &self, role_id: &str, org_id: &id_type::OrganizationId, diff --git a/crates/router/src/services/authorization.rs b/crates/router/src/services/authorization.rs index e0feaa5e817a..2b7e8bd73406 100644 --- a/crates/router/src/services/authorization.rs +++ b/crates/router/src/services/authorization.rs @@ -33,8 +33,7 @@ where return Ok(role_info.clone()); } - let role_info = - get_role_info_from_db(state, &token.role_id, &token.merchant_id, &token.org_id).await?; + let role_info = get_role_info_from_db(state, &token.role_id, &token.org_id).await?; let token_expiry = i64::try_from(token.exp).change_context(ApiErrorResponse::InternalServerError)?; @@ -68,7 +67,6 @@ pub fn get_cache_key_from_role_id(role_id: &str) -> String { async fn get_role_info_from_db( state: &A, role_id: &str, - merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, ) -> RouterResult where @@ -76,7 +74,7 @@ where { state .store() - .find_role_by_role_id_in_merchant_scope(role_id, merchant_id, org_id) + .find_by_role_id_and_org_id(role_id, org_id) .await .map(roles::RoleInfo::from) .to_not_found_response(ApiErrorResponse::InvalidJwtToken) diff --git a/crates/router/src/services/authorization/roles.rs b/crates/router/src/services/authorization/roles.rs index a6c5cee1c4ea..dcffa3107c91 100644 --- a/crates/router/src/services/authorization/roles.rs +++ b/crates/router/src/services/authorization/roles.rs @@ -116,7 +116,7 @@ impl RoleInfo { acl } - pub async fn from_role_id_in_merchant_scope( + pub async fn from_role_id_in_lineage( state: &SessionState, role_id: &str, merchant_id: &id_type::MerchantId, @@ -127,13 +127,13 @@ impl RoleInfo { } else { state .store - .find_role_by_role_id_in_merchant_scope(role_id, merchant_id, org_id) + .find_role_by_role_id_in_lineage(role_id, merchant_id, org_id) .await .map(Self::from) } } - pub async fn from_role_id_in_org_scope( + pub async fn from_role_id_and_org_id( state: &SessionState, role_id: &str, org_id: &id_type::OrganizationId, @@ -143,7 +143,7 @@ impl RoleInfo { } else { state .store - .find_role_by_role_id_in_org_scope(role_id, org_id) + .find_by_role_id_and_org_id(role_id, org_id) .await .map(Self::from) } diff --git a/crates/router/src/types/domain/user/decision_manager.rs b/crates/router/src/types/domain/user/decision_manager.rs index 519edf4e9ce5..bf5556dd9a75 100644 --- a/crates/router/src/types/domain/user/decision_manager.rs +++ b/crates/router/src/types/domain/user/decision_manager.rs @@ -337,8 +337,7 @@ impl NextFlow { .change_context(UserErrors::InternalServerError)? .pop() .ok_or(UserErrors::InternalServerError)?; - utils::user_role::set_role_permissions_in_cache_by_user_role(state, &user_role) - .await; + utils::user_role::set_role_info_in_cache_by_user_role(state, &user_role).await; jwt_flow.generate_jwt(state, self, &user_role).await } @@ -357,8 +356,7 @@ impl NextFlow { { self.user.get_verification_days_left(state)?; } - utils::user_role::set_role_permissions_in_cache_by_user_role(state, user_role) - .await; + utils::user_role::set_role_info_in_cache_by_user_role(state, user_role).await; jwt_flow.generate_jwt(state, self, user_role).await } diff --git a/crates/router/src/utils/user.rs b/crates/router/src/utils/user.rs index 9886705ec66b..abd59684243c 100644 --- a/crates/router/src/utils/user.rs +++ b/crates/router/src/utils/user.rs @@ -77,14 +77,9 @@ impl UserFromToken { } pub async fn get_role_info_from_db(&self, state: &SessionState) -> UserResult { - RoleInfo::from_role_id_in_merchant_scope( - state, - &self.role_id, - &self.merchant_id, - &self.org_id, - ) - .await - .change_context(UserErrors::InternalServerError) + RoleInfo::from_role_id_and_org_id(state, &self.role_id, &self.org_id) + .await + .change_context(UserErrors::InternalServerError) } } diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs index 3412219d0e97..b8f93bff943c 100644 --- a/crates/router/src/utils/user_role.rs +++ b/crates/router/src/utils/user_role.rs @@ -71,55 +71,43 @@ pub async fn validate_role_name( Ok(()) } -pub async fn set_role_permissions_in_cache_by_user_role( +pub async fn set_role_info_in_cache_by_user_role( state: &SessionState, user_role: &UserRole, ) -> bool { - let Some(ref merchant_id) = user_role.merchant_id else { - return false; - }; - let Some(ref org_id) = user_role.org_id else { return false; }; - set_role_permissions_in_cache_if_required( - state, - user_role.role_id.as_str(), - merchant_id, - org_id, - ) - .await - .map_err(|e| logger::error!("Error setting permissions in cache {:?}", e)) - .is_ok() + set_role_info_in_cache_if_required(state, user_role.role_id.as_str(), org_id) + .await + .map_err(|e| logger::error!("Error setting permissions in cache {:?}", e)) + .is_ok() } -pub async fn set_role_permissions_in_cache_by_role_id_merchant_id_org_id( +pub async fn set_role_info_in_cache_by_role_id_org_id( state: &SessionState, role_id: &str, - merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, ) -> bool { - set_role_permissions_in_cache_if_required(state, role_id, merchant_id, org_id) + set_role_info_in_cache_if_required(state, role_id, org_id) .await .map_err(|e| logger::error!("Error setting permissions in cache {:?}", e)) .is_ok() } -pub async fn set_role_permissions_in_cache_if_required( +pub async fn set_role_info_in_cache_if_required( state: &SessionState, role_id: &str, - merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, ) -> UserResult<()> { if roles::predefined_roles::PREDEFINED_ROLES.contains_key(role_id) { return Ok(()); } - let role_info = - roles::RoleInfo::from_role_id_in_merchant_scope(state, role_id, merchant_id, org_id) - .await - .change_context(UserErrors::InternalServerError) - .attach_printable("Error getting role_info from role_id")?; + let role_info = roles::RoleInfo::from_role_id_and_org_id(state, role_id, org_id) + .await + .change_context(UserErrors::InternalServerError) + .attach_printable("Error getting role_info from role_id")?; authz::set_role_info_in_cache( state, diff --git a/migrations/2024-12-02-110129_update-user-role-entity-type/down.sql b/migrations/2024-12-02-110129_update-user-role-entity-type/down.sql new file mode 100644 index 000000000000..c7c9cbeb4017 --- /dev/null +++ b/migrations/2024-12-02-110129_update-user-role-entity-type/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +SELECT 1; \ No newline at end of file diff --git a/migrations/2024-12-02-110129_update-user-role-entity-type/up.sql b/migrations/2024-12-02-110129_update-user-role-entity-type/up.sql new file mode 100644 index 000000000000..f2759f030d50 --- /dev/null +++ b/migrations/2024-12-02-110129_update-user-role-entity-type/up.sql @@ -0,0 +1,10 @@ +-- Your SQL goes here +UPDATE user_roles +SET + entity_type = CASE + WHEN role_id = 'org_admin' THEN 'organization' + ELSE 'merchant' + END +WHERE + version = 'v1' + AND entity_type IS NULL; \ No newline at end of file From 9f0d8efa8dad45a773f4cab6978288f2209e4abf Mon Sep 17 00:00:00 2001 From: Prasunna Soppa <70575890+prasunna09@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:51:12 +0530 Subject: [PATCH 11/51] fix(core): add validation to check if routable connector supports network tokenization in CIT repeat flow (#6749) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/router/src/core/payment_methods.rs | 2 ++ crates/router/src/core/payments/helpers.rs | 28 +++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 53ec01298967..041fb52091ba 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -588,6 +588,7 @@ pub async fn retrieve_payment_method_with_token( mandate_id, payment_method_info, business_profile, + payment_attempt.connector.clone(), ) .await .map(|card| Some((card, enums::PaymentMethod::Card)))? @@ -622,6 +623,7 @@ pub async fn retrieve_payment_method_with_token( mandate_id, payment_method_info, business_profile, + payment_attempt.connector.clone(), ) .await .map(|card| Some((card, enums::PaymentMethod::Card)))? diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 01bac9a21242..923f6d24fe83 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1916,6 +1916,7 @@ pub async fn retrieve_card_with_permanent_token( mandate_id: Option, payment_method_info: Option, business_profile: &domain::Profile, + connector: Option, ) -> RouterResult { let customer_id = payment_intent .customer_id @@ -1986,7 +1987,28 @@ pub async fn retrieve_card_with_permanent_token( .attach_printable("Payment method data is not present"), (Some(ref pm_data), None) => { // Regular (non-mandate) Payment flow - if let Some(token_ref) = pm_data.network_token_requestor_reference_id.clone() { + let network_tokenization_supported_connectors = &state + .conf + .network_tokenization_supported_connectors + .connector_list; + let connector_variant = connector + .as_ref() + .map(|conn| { + api_enums::Connector::from_str(conn.as_str()) + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "connector", + }) + .attach_printable_lazy(|| { + format!("unable to parse connector name {connector:?}") + }) + }) + .transpose()?; + if let (Some(_conn), Some(token_ref)) = ( + connector_variant + .filter(|conn| network_tokenization_supported_connectors.contains(conn)), + pm_data.network_token_requestor_reference_id.clone(), + ) { + logger::info!("Fetching network token data from tokenization service"); match network_tokenization::get_token_from_tokenization_service( state, token_ref, pm_data, ) @@ -2016,6 +2038,8 @@ pub async fn retrieve_card_with_permanent_token( } } } else { + logger::info!("Either the connector is not in the NT supported list or token requestor reference ID is absent"); + logger::info!("Falling back to fetch card details from locker"); fetch_card_details_from_locker( state, customer_id, @@ -5773,6 +5797,7 @@ pub async fn get_payment_method_details_from_payment_token( None, None, business_profile, + payment_attempt.connector.clone(), ) .await .map(|card| Some((card, enums::PaymentMethod::Card))), @@ -5791,6 +5816,7 @@ pub async fn get_payment_method_details_from_payment_token( None, None, business_profile, + payment_attempt.connector.clone(), ) .await .map(|card| Some((card, enums::PaymentMethod::Card))), From 08ab3ad7a2e60bc35332be606941793bc6a8a32f Mon Sep 17 00:00:00 2001 From: likhinbopanna <131246334+likhinbopanna@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:51:49 +0530 Subject: [PATCH 12/51] ci(cypress): Add shipping cost test case (#6779) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- .../00004-NoThreeDSAutoCapture.cy.js | 48 +++++++++++++++++++ .../cypress/e2e/PaymentUtils/Adyen.js | 34 +++++++++++++ .../cypress/e2e/PaymentUtils/BankOfAmerica.js | 34 +++++++++++++ .../cypress/e2e/PaymentUtils/Bluesnap.js | 35 ++++++++++++++ .../cypress/e2e/PaymentUtils/Checkout.js | 32 +++++++++++++ .../cypress/e2e/PaymentUtils/Commons.js | 26 ++++++++++ .../cypress/e2e/PaymentUtils/Cybersource.js | 34 +++++++++++++ cypress-tests/cypress/e2e/PaymentUtils/Nmi.js | 32 +++++++++++++ .../cypress/e2e/PaymentUtils/Noon.js | 32 +++++++++++++ .../cypress/e2e/PaymentUtils/Paypal.js | 33 +++++++++++++ .../cypress/e2e/PaymentUtils/Stripe.js | 34 +++++++++++++ .../cypress/e2e/PaymentUtils/Trustpay.js | 34 +++++++++++++ cypress-tests/cypress/support/commands.js | 14 ++++-- 13 files changed, 419 insertions(+), 3 deletions(-) diff --git a/cypress-tests/cypress/e2e/PaymentTest/00004-NoThreeDSAutoCapture.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00004-NoThreeDSAutoCapture.cy.js index 62f4af2338c3..e5030647cb7c 100644 --- a/cypress-tests/cypress/e2e/PaymentTest/00004-NoThreeDSAutoCapture.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00004-NoThreeDSAutoCapture.cy.js @@ -96,4 +96,52 @@ describe("Card - NoThreeDS payment flow test", () => { cy.retrievePaymentCallTest(globalState, data); }); }); + + context("Card-NoThreeDS payment with shipping cost", () => { + let shouldContinue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!shouldContinue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + const data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntentWithShippingCost"]; + + cy.createPaymentIntentTest( + fixtures.createPaymentBody, + data, + "no_three_ds", + "automatic", + globalState + ); + + if (shouldContinue) shouldContinue = utils.should_continue_further(data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm No 3DS", () => { + const data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentConfirmWithShippingCost"]; + + cy.confirmCallTest(fixtures.confirmBody, data, true, globalState); + + if (shouldContinue) shouldContinue = utils.should_continue_further(data); + }); + + it("retrieve-payment-call-test", () => { + const data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentConfirmWithShippingCost"]; + + cy.retrievePaymentCallTest(globalState, data); + }); + }); }); diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Adyen.js b/cypress-tests/cypress/e2e/PaymentUtils/Adyen.js index db3206e5dde5..1fc4cf96494b 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Adyen.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Adyen.js @@ -80,6 +80,40 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + shipping_cost: 50, + amount_received: 6550, + amount: 6500, + net_amount: 6550, + }, + }, + }, "3DSManualCapture": { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js b/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js index a5af06b908a2..308565e72fa4 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js @@ -78,6 +78,40 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + amount: 6500, + shipping_cost: 50, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + shipping_cost: 50, + amount_received: 6550, + amount: 6500, + net_amount: 6550, + }, + }, + }, "3DSManualCapture": { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js b/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js index 708a8660d520..f27b7ef76c1f 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js @@ -29,6 +29,41 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + amount: 6500, + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + amount: 6500, + shipping_cost: 50, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + shipping_cost: 50, + amount_received: 6550, + amount: 6500, + net_amount: 6550, + }, + }, + }, "3DSManualCapture": { Configs: { TRIGGER_SKIP: true, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Checkout.js b/cypress-tests/cypress/e2e/PaymentUtils/Checkout.js index 3307e90c3718..9679b70866bc 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Checkout.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Checkout.js @@ -38,6 +38,38 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + shipping_cost: 50, + amount: 6500, + }, + }, + }, "3DSManualCapture": { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js index 28b85c854465..a258d7fa0db1 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js @@ -637,9 +637,35 @@ export const connectorDetails = { status: 200, body: { status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, }, }, }), + PaymentIntentWithShippingCost: getCustomExchange({ + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }), + PaymentConfirmWithShippingCost: getCustomExchange({ + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + }), "3DSManualCapture": getCustomExchange({ Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js index ea7fe7b7acb1..0c489f6df835 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js @@ -146,6 +146,40 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + shipping_cost: 50, + amount_received: 6550, + amount: 6500, + net_amount: 6550, + }, + }, + }, "3DSManualCapture": { Configs: { CONNECTOR_CREDENTIAL: { diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js b/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js index 2ece2615b4c1..8ad218953ddd 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js @@ -38,6 +38,38 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + shipping_cost: 50, + amount: 6500, + }, + }, + }, "3DSManualCapture": { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Noon.js b/cypress-tests/cypress/e2e/PaymentUtils/Noon.js index 6d2a3926972e..63f6b6317324 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Noon.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Noon.js @@ -115,6 +115,38 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "AED", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + shipping_cost: 50, + amount: 6500, + }, + }, + }, "3DSManualCapture": { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js b/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js index a551ed859593..024ad7377b34 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js @@ -48,6 +48,39 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "failed", + error_code: "AMOUNT_MISMATCH", + error_message: + "description - Should equal item_total + tax_total + shipping + handling + insurance - shipping_discount - discount., value - 65.50, field - value;", + }, + }, + }, "3DSManualCapture": { Configs: { TRIGGER_SKIP: true, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js index d68978c43023..4e62c37c5b05 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js @@ -141,6 +141,40 @@ export const connectorDetails = { }, }, }, + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + shipping_cost: 50, + amount_received: 6550, + amount: 6500, + net_amount: 6550, + }, + }, + }, "3DSManualCapture": { Request: { payment_method: "card", diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Trustpay.js b/cypress-tests/cypress/e2e/PaymentUtils/Trustpay.js index 76351c6c4548..6c4db9df329b 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Trustpay.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Trustpay.js @@ -54,6 +54,40 @@ export const connectorDetails = { }, }, }), + PaymentIntentWithShippingCost: { + Request: { + currency: "USD", + shipping_cost: 50, + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + shipping_cost: 50, + amount: 6500, + }, + }, + }, + PaymentConfirmWithShippingCost: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + shipping_cost: 50, + amount_received: 6550, + amount: 6500, + net_amount: 6550, + }, + }, + }, "3DSAutoCapture": { Configs: { CONNECTOR_CREDENTIAL: { diff --git a/cypress-tests/cypress/support/commands.js b/cypress-tests/cypress/support/commands.js index f3ce856fe38a..89691f041018 100644 --- a/cypress-tests/cypress/support/commands.js +++ b/cypress-tests/cypress/support/commands.js @@ -1079,9 +1079,17 @@ Cypress.Commands.add( createPaymentBody.setup_future_usage, "setup_future_usage" ).to.equal(response.body.setup_future_usage); - expect(createPaymentBody.amount, "amount_capturable").to.equal( - response.body.amount_capturable - ); + // If 'shipping_cost' is not included in the request, the 'amount' in 'createPaymentBody' should match the 'amount_capturable' in the response. + if (typeof createPaymentBody?.shipping_cost === "undefined") { + expect(createPaymentBody.amount, "amount_capturable").to.equal( + response.body.amount_capturable + ); + } else { + expect( + createPaymentBody.amount + createPaymentBody.shipping_cost, + "amount_capturable" + ).to.equal(response.body.amount_capturable); + } expect(response.body.amount_received, "amount_received").to.be.oneOf([ 0, null, From 84318427108a0f974b2519587d0e336807a9600c Mon Sep 17 00:00:00 2001 From: Debarati Ghatak <88573135+cookieg13@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:05:19 +0530 Subject: [PATCH 13/51] feat(payments): [Payment links] Add locale case fix (#6789) --- crates/router/src/core/payment_link/locale.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/router/src/core/payment_link/locale.js b/crates/router/src/core/payment_link/locale.js index e1ed69f7a1ae..114376bf9f9f 100644 --- a/crates/router/src/core/payment_link/locale.js +++ b/crates/router/src/core/payment_link/locale.js @@ -3,11 +3,11 @@ The languages supported by locale.js are: 1) English (en) 2) Hebrew (he) 3) French (fr) - 4) British English (en_GB) + 4) British English (en_gb) 5) Arabic (ar) 6) Japanese (ja) 7) German (de) - 8) Belgian French (fr_BE) + 8) Belgian French (fr_be) 9) Spanish (es) 10) Catalan (ca) 11) Portuguese (pt) @@ -17,7 +17,7 @@ The languages supported by locale.js are: 15) Swedish (sv) 16) Russian (ru) 17) Chinese (zh) - 19) Traditional Chinese (zh_Hant) + 19) Traditional Chinese (zh_hant) */ const locales = { en: { @@ -113,7 +113,7 @@ const locales = { errorCode: "Code d'erreur", errorMessage: "Message d'erreur" }, - en_GB: { + en_gb: { expiresOn: "Link expires on: ", refId: "Ref Id: ", requestedBy: "Requested by ", @@ -238,7 +238,7 @@ const locales = { errorCode: "Fehlercode", errorMessage: "Fehlermeldung" }, - fr_BE: { + fr_be: { expiresOn: "Le lien expire le: ", refId: "ID de référence: ", requestedBy: "Demandé par ", @@ -550,7 +550,7 @@ const locales = { errorCode: "错误代码", errorMessage: "错误信息" }, - zh_Hant: { + zh_hant: { expiresOn: "連結到期日期:", refId: "參考編號:", requestedBy: "請求者 ", @@ -584,6 +584,7 @@ const locales = { }; function getTranslations(locale_str) { - var locale = locale_str || 'en'; // defaults if locale is not present in payment details. + var fallback_locale = 'en'; + var locale = locale_str.toLowerCase().replace(/-/g, "_") || fallback_locale; // defaults if locale is not present in payment details. return locales[locale] || locales['en']; // defaults if locale is not implemented in locales. } \ No newline at end of file From c3b22cf81a5c8cbc6538ca7f7e4b1ce4d18eb644 Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 10 Dec 2024 21:44:59 +0530 Subject: [PATCH 14/51] fix(core): payments - map billing first and last name to card holder name (#6791) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/api_models/src/payments.rs | 29 ++++++++++++++----- .../src/payment_method_data.rs | 7 ++++- .../router/src/core/payment_methods/vault.rs | 2 ++ crates/router/src/core/payments/helpers.rs | 14 +++++---- crates/router/src/utils/verify_connector.rs | 1 + crates/router/tests/connectors/aci.rs | 2 ++ crates/router/tests/connectors/adyen.rs | 1 + crates/router/tests/connectors/airwallex.rs | 1 + crates/router/tests/connectors/fiserv.rs | 1 + crates/router/tests/connectors/rapyd.rs | 2 ++ crates/router/tests/connectors/utils.rs | 1 + crates/router/tests/connectors/worldline.rs | 1 + .../cypress/e2e/PaymentUtils/Cybersource.js | 4 +-- .../cypress/e2e/PaymentUtils/Stripe.js | 4 +-- 14 files changed, 52 insertions(+), 18 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 6a7f7148bd3a..cab8071de087 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2092,14 +2092,29 @@ mod payment_method_data_serde { if inner_map.is_empty() { None } else { - Some( - serde_json::from_value::( - payment_method_data_value, - ) - .map_err(|serde_json_error| { - de::Error::custom(serde_json_error.to_string()) - })?, + let payment_method_data = serde_json::from_value::( + payment_method_data_value, ) + .map_err(|serde_json_error| { + de::Error::custom(serde_json_error.to_string()) + })?; + let address_details = parsed_value + .billing + .as_ref() + .and_then(|billing| billing.address.clone()); + match (payment_method_data.clone(), address_details.as_ref()) { + ( + PaymentMethodData::Card(ref mut card), + Some(billing_address_details), + ) => { + if card.card_holder_name.is_none() { + card.card_holder_name = + billing_address_details.get_optional_full_name(); + } + Some(PaymentMethodData::Card(card.clone())) + } + _ => Some(payment_method_data), + } } } else { Err(de::Error::custom("Expected a map for payment_method_data"))? diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 820959a59637..db35766f33ae 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -82,6 +82,7 @@ pub struct Card { pub card_issuing_country: Option, pub bank_code: Option, pub nick_name: Option>, + pub card_holder_name: Option>, } #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)] @@ -95,6 +96,7 @@ pub struct CardDetailsForNetworkTransactionId { pub card_issuing_country: Option, pub bank_code: Option, pub nick_name: Option>, + pub card_holder_name: Option>, } impl CardDetailsForNetworkTransactionId { @@ -136,6 +138,7 @@ impl From for CardDetailsForNetwor card_issuing_country: card_details_for_nti.card_issuing_country, bank_code: card_details_for_nti.bank_code, nick_name: card_details_for_nti.nick_name, + card_holder_name: card_details_for_nti.card_holder_name, } } } @@ -666,7 +669,7 @@ impl From for Card { card_number, card_exp_month, card_exp_year, - card_holder_name: _, + card_holder_name, card_cvc, card_issuer, card_network, @@ -687,6 +690,7 @@ impl From for Card { card_issuing_country, bank_code, nick_name, + card_holder_name, } } } @@ -1438,6 +1442,7 @@ pub struct TokenizedCardValue1 { pub nickname: Option, pub card_last_four: Option, pub card_token: Option, + pub card_holder_name: Option>, } #[derive(Debug, serde::Serialize, serde::Deserialize)] diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs index 32a42d301659..fcff711f6c9a 100644 --- a/crates/router/src/core/payment_methods/vault.rs +++ b/crates/router/src/core/payment_methods/vault.rs @@ -66,6 +66,7 @@ impl Vaultable for domain::Card { nickname: self.nick_name.as_ref().map(|name| name.peek().clone()), card_last_four: None, card_token: None, + card_holder_name: self.card_holder_name.clone(), }; value1 @@ -119,6 +120,7 @@ impl Vaultable for domain::Card { card_issuing_country: None, card_type: None, nick_name: value1.nickname.map(masking::Secret::new), + card_holder_name: value1.card_holder_name, }; let supp_data = SupplementaryVaultData { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 923f6d24fe83..4771360ea7f2 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1962,6 +1962,7 @@ pub async fn retrieve_card_with_permanent_token( card_issuing_country: None, bank_code: None, nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), + card_holder_name: card_details_from_locker.name_on_card.clone(), }; Ok( @@ -2130,6 +2131,7 @@ pub async fn retrieve_card_with_permanent_token( card_issuing_country: None, bank_code: None, nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), + card_holder_name: card_details_from_locker.name_on_card, }; Ok( @@ -4408,7 +4410,7 @@ pub async fn get_additional_payment_data( bank_code: card_data.bank_code.to_owned(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), last4: last4.clone(), card_isin: card_isin.clone(), card_extended_bin: card_extended_bin.clone(), @@ -4441,7 +4443,7 @@ pub async fn get_additional_payment_data( card_extended_bin: card_extended_bin.clone(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, @@ -4461,7 +4463,7 @@ pub async fn get_additional_payment_data( card_extended_bin, card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, @@ -4671,7 +4673,7 @@ pub async fn get_additional_payment_data( bank_code: card_data.bank_code.to_owned(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), last4: last4.clone(), card_isin: card_isin.clone(), card_extended_bin: card_extended_bin.clone(), @@ -4704,7 +4706,7 @@ pub async fn get_additional_payment_data( card_extended_bin: card_extended_bin.clone(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, @@ -4724,7 +4726,7 @@ pub async fn get_additional_payment_data( card_extended_bin, card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, diff --git a/crates/router/src/utils/verify_connector.rs b/crates/router/src/utils/verify_connector.rs index 617cb415ee00..b13ba70e6fbd 100644 --- a/crates/router/src/utils/verify_connector.rs +++ b/crates/router/src/utils/verify_connector.rs @@ -23,6 +23,7 @@ pub fn generate_card_from_details( card_type: None, card_issuing_country: None, bank_code: None, + card_holder_name: None, }) } diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index d8607946b500..2d0272cfa7e6 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -51,6 +51,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), confirm: true, statement_descriptor_suffix: None, @@ -296,6 +297,7 @@ async fn payments_create_failure() { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }); let response = services::api::execute_connector_processing_step( diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs index 2146d9590020..c7ad3b69a320 100644 --- a/crates/router/tests/connectors/adyen.rs +++ b/crates/router/tests/connectors/adyen.rs @@ -153,6 +153,7 @@ impl AdyenTest { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), confirm: true, statement_descriptor_suffix: None, diff --git a/crates/router/tests/connectors/airwallex.rs b/crates/router/tests/connectors/airwallex.rs index bbc387a0b226..0e538818d50a 100644 --- a/crates/router/tests/connectors/airwallex.rs +++ b/crates/router/tests/connectors/airwallex.rs @@ -82,6 +82,7 @@ fn payment_method_details() -> Option { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), capture_method: Some(diesel_models::enums::CaptureMethod::Manual), router_return_url: Some("https://google.com".to_string()), diff --git a/crates/router/tests/connectors/fiserv.rs b/crates/router/tests/connectors/fiserv.rs index bfa16d74f548..7f13de310044 100644 --- a/crates/router/tests/connectors/fiserv.rs +++ b/crates/router/tests/connectors/fiserv.rs @@ -53,6 +53,7 @@ fn payment_method_details() -> Option { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), capture_method: Some(diesel_models::enums::CaptureMethod::Manual), ..utils::PaymentAuthorizeType::default().0 diff --git a/crates/router/tests/connectors/rapyd.rs b/crates/router/tests/connectors/rapyd.rs index ff083a37e595..ee6ac303e88e 100644 --- a/crates/router/tests/connectors/rapyd.rs +++ b/crates/router/tests/connectors/rapyd.rs @@ -53,6 +53,7 @@ async fn should_only_authorize_payment() { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), capture_method: Some(diesel_models::enums::CaptureMethod::Manual), ..utils::PaymentAuthorizeType::default().0 @@ -80,6 +81,7 @@ async fn should_authorize_and_capture_payment() { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), ..utils::PaymentAuthorizeType::default().0 }), diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index c08139ae6fe0..18c171d58c57 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -927,6 +927,7 @@ impl Default for CCardType { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }) } } diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs index c1be90b59fde..793a1cc15f4a 100644 --- a/crates/router/tests/connectors/worldline.rs +++ b/crates/router/tests/connectors/worldline.rs @@ -83,6 +83,7 @@ impl WorldlineTest { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), confirm: true, statement_descriptor_suffix: None, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js index 0c489f6df835..98d8e4c1acb4 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js @@ -59,7 +59,7 @@ const payment_method_data_no3ds = { card_extended_bin: null, card_exp_month: "01", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "joseph Doe", payment_checks: { avs_response: { code: "Y", @@ -83,7 +83,7 @@ const payment_method_data_3ds = { card_extended_bin: null, card_exp_month: "01", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "joseph Doe", payment_checks: null, authentication_data: null, }, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js index 4e62c37c5b05..4228a5115355 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js @@ -61,7 +61,7 @@ const payment_method_data_3ds = { card_extended_bin: null, card_exp_month: "10", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "morino", payment_checks: null, authentication_data: null, }, @@ -79,7 +79,7 @@ const payment_method_data_no3ds = { card_extended_bin: null, card_exp_month: "10", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "morino", payment_checks: { cvc_check: "pass", address_line1_check: "pass", From 400d9a42de4cb99e3e2d7dc69510f503661700e4 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:22:31 +0000 Subject: [PATCH 15/51] chore(version): 2024.12.11.0 --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8a4155e14e..3325b5029997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,41 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.12.11.0 + +### Features + +- **analytics:** Add support for multiple emails as input to forward reports ([#6776](https://github.com/juspay/hyperswitch/pull/6776)) ([`3df4233`](https://github.com/juspay/hyperswitch/commit/3df42333566b646e9ca93d612a78ea8d38298df4)) +- **connector:** [Unifiedauthenticationservice] add Connector Template Code ([#6732](https://github.com/juspay/hyperswitch/pull/6732)) ([`8777f41`](https://github.com/juspay/hyperswitch/commit/8777f41568ebf5373917089d7d42f3b14fb1bf60)) +- **payments:** [Payment links] Add locale case fix ([#6789](https://github.com/juspay/hyperswitch/pull/6789)) ([`8431842`](https://github.com/juspay/hyperswitch/commit/84318427108a0f974b2519587d0e336807a9600c)) + +### Bug Fixes + +- **core:** + - Add validation to check if routable connector supports network tokenization in CIT repeat flow ([#6749](https://github.com/juspay/hyperswitch/pull/6749)) ([`9f0d8ef`](https://github.com/juspay/hyperswitch/commit/9f0d8efa8dad45a773f4cab6978288f2209e4abf)) + - Payments - map billing first and last name to card holder name ([#6791](https://github.com/juspay/hyperswitch/pull/6791)) ([`c3b22cf`](https://github.com/juspay/hyperswitch/commit/c3b22cf81a5c8cbc6538ca7f7e4b1ce4d18eb644)) +- **docs:** Incorrect description for refund api ([#6443](https://github.com/juspay/hyperswitch/pull/6443)) ([`8954e8a`](https://github.com/juspay/hyperswitch/commit/8954e8a2180d20719b1bb0d4f77081ff03fd9b43)) + +### Refactors + +- **constraint_graph:** Add setup_future_usage for mandate check in payments ([#6744](https://github.com/juspay/hyperswitch/pull/6744)) ([`1aa4ad6`](https://github.com/juspay/hyperswitch/commit/1aa4ad60e2326cbdc5c81479cf3420c3f3e1d8ee)) +- **enums:** Recon - include ReconOps variant in PermissionsGroup for backwards compatibility with data in DB ([#6767](https://github.com/juspay/hyperswitch/pull/6767)) ([`a528282`](https://github.com/juspay/hyperswitch/commit/a52828296a682e30badf0849921469cdf4eecbea)) +- **events:** Tenant config in API, Connector and Outgoing Web-hook events ([#6777](https://github.com/juspay/hyperswitch/pull/6777)) ([`c620779`](https://github.com/juspay/hyperswitch/commit/c620779bbd14a1102d4fff68cc36581935d87da7)) +- **payment_methods:** Add new field_type UserBsbNumber, UserBankSortCode and UserBankRoutingNumber for payment_connector_required_fields ([#6758](https://github.com/juspay/hyperswitch/pull/6758)) ([`6f84145`](https://github.com/juspay/hyperswitch/commit/6f841458f73cec8ce43a34b1b50abbc74baa2ef7)) +- **users:** Remove lineage checks in roles get operations ([#6701](https://github.com/juspay/hyperswitch/pull/6701)) ([`f96a87d`](https://github.com/juspay/hyperswitch/commit/f96a87d08ca003411d63dcd9ef4dda6439d20e07)) + +### Documentation + +- Add new logos for README and API reference ([#6783](https://github.com/juspay/hyperswitch/pull/6783)) ([`b9c04c3`](https://github.com/juspay/hyperswitch/commit/b9c04c39880aa1ab0b66397802d138f0d4c1ed28)) + +### Build System / Dependencies + +- **deps:** Bump opentelemetry crates to 0.27 ([#6774](https://github.com/juspay/hyperswitch/pull/6774)) ([`47a3d2b`](https://github.com/juspay/hyperswitch/commit/47a3d2b2abcc28a13f79bd9318d119f103b7fb6c)) + +**Full Changelog:** [`2024.12.10.0...2024.12.11.0`](https://github.com/juspay/hyperswitch/compare/2024.12.10.0...2024.12.11.0) + +- - - + ## 2024.12.10.0 ### Features From cd205378c035780586f6b94e5c9e03466165a33b Mon Sep 17 00:00:00 2001 From: Sakil Mostak <73734619+Sakilmostak@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:43:43 +0530 Subject: [PATCH 16/51] fix(router): card network for co-badged card and update regex (#6801) --- crates/cards/src/validate.rs | 28 +++++++++++++--------- crates/router/src/core/payments/helpers.rs | 4 ++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/crates/cards/src/validate.rs b/crates/cards/src/validate.rs index d3a27da4823b..725d05b4807f 100644 --- a/crates/cards/src/validate.rs +++ b/crates/cards/src/validate.rs @@ -51,26 +51,32 @@ impl CardNumber { static CARD_NETWORK_REGEX: Lazy>> = Lazy::new( || { let mut map = HashMap::new(); - map.insert("Mastercard", Regex::new(r"^(5[1-5][0-9]{14}|2(2(2[1-9]|[3-9][0-9])|[3-6][0-9][0-9]|7([0-1][0-9]|20))[0-9]{12})$")); - map.insert("American Express", Regex::new(r"^3[47][0-9]{13}$")); - map.insert("Visa", Regex::new(r"^4[0-9]{12}(?:[0-9]{3})?$")); - map.insert("Discover", Regex::new(r"^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})$")); + map.insert( + "Mastercard", + Regex::new(r"^(222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[0-1][0-9]|2720|5[1-5])"), + ); + map.insert("American Express", Regex::new(r"^3[47]")); + map.insert("Visa", Regex::new(r"^4")); + map.insert( + "Discover", + Regex::new( + r"^(6011|64[4-9]|65|622126|622[1-9][0-9][0-9]|6229[0-1][0-9]|622925)", + ), + ); map.insert( "Maestro", - Regex::new(r"^(5018|5081|5044|504681|504993|5020|502260|5038|603845|603123|6304|6759|676[1-3]|6220|504834|504817|504645|504775|600206|627741)"), + Regex::new(r"^(5018|5081|5044|504681|504993|5020|502260|5038|5893|603845|603123|6304|6759|676[1-3]|6220|504834|504817|504645|504775|600206|627741)"), ); map.insert( "RuPay", - Regex::new(r"^(508227|508[5-9]|603741|60698[5-9]|60699|607[0-8]|6079[0-7]|60798[0-4]|60800[1-9]|6080[1-9]|608[1-4]|608500|6521[5-9]|652[2-9]|6530|6531[0-4]|817290|817368|817378|353800)"), + Regex::new(r"^(508227|508[5-9]|603741|60698[5-9]|60699|607[0-8]|6079[0-7]|60798[0-4]|60800[1-9]|6080[1-9]|608[1-4]|608500|6521[5-9]|652[2-9]|6530|6531[0-4]|817290|817368|817378|353800|82)"), ); - map.insert("Diners Club", Regex::new(r"^(36|38|30[0-5])")); - map.insert( - "JCB", - Regex::new(r"^(3(?:088|096|112|158|337|5(?:2[89]|[3-8][0-9]))\d{12})$"), - ); + map.insert("Diners Club", Regex::new(r"^(36|38|39|30[0-5])")); + map.insert("JCB", Regex::new(r"^35(2[89]|[3-8][0-9])")); map.insert("CarteBlanche", Regex::new(r"^389[0-9]{11}$")); map.insert("Sodex", Regex::new(r"^(637513)")); map.insert("BAJAJ", Regex::new(r"^(203040)")); + map.insert("CartesBancaires", Regex::new(r"^(401(005|006|581)|4021(01|02)|403550|405936|406572|41(3849|4819|50(56|59|62|71|74)|6286|65(37|79)|71[7])|420110|423460|43(47(21|22)|50(48|49|50|51|52)|7875|95(09|11|15|39|98)|96(03|18|19|20|22|72))|4424(48|49|50|51|52|57)|448412|4505(19|60)|45(33|56[6-8]|61|62[^3]|6955|7452|7717|93[02379])|46(099|54(76|77)|6258|6575|98[023])|47(4107|71(73|74|86)|72(65|93)|9619)|48(1091|3622|6519)|49(7|83[5-9]|90(0[1-6]|1[0-6]|2[0-3]|3[0-3]|4[0-3]|5[0-2]|68|9[256789]))|5075(89|90|93|94|97)|51(0726|3([0-7]|8[56]|9(00|38))|5214|62(07|36)|72(22|43)|73(65|66)|7502|7647|8101|9920)|52(0993|1662|3718|7429|9227|93(13|14|31)|94(14|21|30|40|47|55|56|[6-9])|9542)|53(0901|10(28|30)|1195|23(4[4-7])|2459|25(09|34|54|56)|3801|41(02|05|11)|50(29|66)|5324|61(07|15)|71(06|12)|8011)|54(2848|5157|9538|98(5[89]))|55(39(79|93)|42(05|60)|4965|7008|88(67|82)|89(29|4[23])|9618|98(09|10))|56(0408|12(0[2-6]|4[134]|5[04678]))|58(17(0[0-7]|15|2[14]|3[16789]|4[0-9]|5[016]|6[269]|7[3789]|8[0-7]|9[017])|55(0[2-5]|7[7-9]|8[0-2])))")); map }, ); diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 4771360ea7f2..61b47df3256f 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -4434,7 +4434,7 @@ pub async fn get_additional_payment_data( api_models::payments::AdditionalPaymentData::Card(Box::new( api_models::payments::AdditionalCardInfo { card_issuer: card_info.card_issuer, - card_network: card_info.card_network, + card_network: card_network.or(card_info.card_network), bank_code: card_info.bank_code, card_type: card_info.card_type, card_issuing_country: card_info.card_issuing_country, @@ -4697,7 +4697,7 @@ pub async fn get_additional_payment_data( api_models::payments::AdditionalPaymentData::Card(Box::new( api_models::payments::AdditionalCardInfo { card_issuer: card_info.card_issuer, - card_network: card_info.card_network, + card_network: card_network.or(card_info.card_network), bank_code: card_info.bank_code, card_type: card_info.card_type, card_issuing_country: card_info.card_issuing_country, From 9466ced89407f31963bb0eb7c762749e3713591a Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 11 Dec 2024 17:32:42 +0530 Subject: [PATCH 17/51] feat(core): Add uas framework support (#6743) Co-authored-by: sai-harsha-vardhan --- crates/diesel_models/src/authentication.rs | 12 + .../src/router_data.rs | 1 + .../src/router_data_v2.rs | 2 +- .../src/router_data_v2/flow_common_types.rs | 6 + .../src/router_request_types.rs | 1 + .../unified_authentication_service.rs | 58 +++++ crates/router/src/core.rs | 2 + .../src/core/authentication/transformers.rs | 1 + .../core/fraud_check/flows/checkout_flow.rs | 1 + .../fraud_check/flows/fulfillment_flow.rs | 1 + .../core/fraud_check/flows/record_return.rs | 1 + .../src/core/fraud_check/flows/sale_flow.rs | 1 + .../fraud_check/flows/transaction_flow.rs | 1 + crates/router/src/core/mandate/utils.rs | 1 + crates/router/src/core/payments.rs | 2 +- .../connector_integration_v2_impls.rs | 111 +++++++++ crates/router/src/core/payments/flows.rs | 226 ++++++++++++++++++ crates/router/src/core/payments/helpers.rs | 1 + crates/router/src/core/payments/operations.rs | 12 + .../payments/operations/payment_approve.rs | 8 +- .../payments/operations/payment_cancel.rs | 10 +- .../payments/operations/payment_capture.rs | 8 +- .../operations/payment_complete_authorize.rs | 10 +- .../payments/operations/payment_confirm.rs | 105 +++++++- .../operations/payment_confirm_intent.rs | 12 +- .../payments/operations/payment_create.rs | 10 +- .../operations/payment_create_intent.rs | 11 +- .../core/payments/operations/payment_get.rs | 18 +- .../payments/operations/payment_get_intent.rs | 13 +- .../operations/payment_post_session_tokens.rs | 9 +- .../payments/operations/payment_reject.rs | 10 +- .../payments/operations/payment_session.rs | 8 +- .../operations/payment_session_intent.rs | 11 +- .../core/payments/operations/payment_start.rs | 8 +- .../payments/operations/payment_status.rs | 16 +- .../payments/operations/payment_update.rs | 10 +- .../payments_incremental_authorization.rs | 10 +- .../payments/operations/tax_calculation.rs | 10 +- .../router/src/core/payments/transformers.rs | 5 + .../core/unified_authentication_service.rs | 187 +++++++++++++++ .../transformers.rs | 36 +++ .../unified_authentication_service/types.rs | 52 ++++ .../unified_authentication_service/utils.rs | 172 +++++++++++++ crates/router/src/core/utils.rs | 8 + crates/router/src/core/webhooks/utils.rs | 1 + crates/router/src/services/api.rs | 3 + .../router/src/services/conversion_impls.rs | 49 +++- crates/router/src/types.rs | 12 +- crates/router/src/types/api.rs | 13 +- .../api/unified_authentication_service.rs | 59 +++++ .../api/unified_authentication_service_v2.rs | 35 +++ .../router/src/types/api/verify_connector.rs | 1 + crates/router/tests/connectors/aci.rs | 2 + crates/router/tests/connectors/utils.rs | 1 + crates/router_derive/src/macros/operation.rs | 4 +- 55 files changed, 1284 insertions(+), 94 deletions(-) create mode 100644 crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs create mode 100644 crates/router/src/core/unified_authentication_service.rs create mode 100644 crates/router/src/core/unified_authentication_service/transformers.rs create mode 100644 crates/router/src/core/unified_authentication_service/types.rs create mode 100644 crates/router/src/core/unified_authentication_service/utils.rs create mode 100644 crates/router/src/types/api/unified_authentication_service.rs create mode 100644 crates/router/src/types/api/unified_authentication_service_v2.rs diff --git a/crates/diesel_models/src/authentication.rs b/crates/diesel_models/src/authentication.rs index 0310e60ebbd8..5d0e58c56270 100644 --- a/crates/diesel_models/src/authentication.rs +++ b/crates/diesel_models/src/authentication.rs @@ -152,6 +152,10 @@ pub enum AuthenticationUpdate { PostAuthorizationUpdate { authentication_lifecycle_status: common_enums::AuthenticationLifecycleStatus, }, + AuthenticationStatusUpdate { + trans_status: common_enums::TransactionStatus, + authentication_status: common_enums::AuthenticationStatus, + }, } #[derive(Clone, Debug, Eq, PartialEq, AsChangeset, Serialize, Deserialize)] @@ -418,6 +422,14 @@ impl From for AuthenticationUpdateInternal { connector_metadata, ..Default::default() }, + AuthenticationUpdate::AuthenticationStatusUpdate { + trans_status, + authentication_status, + } => Self { + trans_status: Some(trans_status), + authentication_status: Some(authentication_status), + ..Default::default() + }, } } } diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index a3867ce3e62a..b070c6bc848a 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -87,6 +87,7 @@ pub struct RouterData { pub connector_mandate_request_reference_id: Option, + pub authentication_id: Option, /// Contains the type of sca exemption required for the transaction pub psd2_sca_exemption_type: Option, } diff --git a/crates/hyperswitch_domain_models/src/router_data_v2.rs b/crates/hyperswitch_domain_models/src/router_data_v2.rs index 9e3a7f255a2e..acc7343cb145 100644 --- a/crates/hyperswitch_domain_models/src/router_data_v2.rs +++ b/crates/hyperswitch_domain_models/src/router_data_v2.rs @@ -8,7 +8,7 @@ pub use flow_common_types::FrmFlowData; pub use flow_common_types::PayoutFlowData; pub use flow_common_types::{ AccessTokenFlowData, DisputesFlowData, ExternalAuthenticationFlowData, FilesFlowData, - MandateRevokeFlowData, PaymentFlowData, RefundFlowData, WebhookSourceVerifyData, + MandateRevokeFlowData, PaymentFlowData, RefundFlowData, UasFlowData, WebhookSourceVerifyData, }; use crate::router_data::{ConnectorAuthType, ErrorResponse}; diff --git a/crates/hyperswitch_domain_models/src/router_data_v2/flow_common_types.rs b/crates/hyperswitch_domain_models/src/router_data_v2/flow_common_types.rs index b2dea40082ac..85028a3bd7fa 100644 --- a/crates/hyperswitch_domain_models/src/router_data_v2/flow_common_types.rs +++ b/crates/hyperswitch_domain_models/src/router_data_v2/flow_common_types.rs @@ -149,3 +149,9 @@ pub struct FilesFlowData { pub connector_meta_data: Option, pub connector_request_reference_id: String, } + +#[derive(Debug, Clone)] +pub struct UasFlowData { + pub authenticate_by: String, + pub source_authentication_id: String, +} diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index b14e27e8453f..7a45faf02629 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -1,5 +1,6 @@ pub mod authentication; pub mod fraud_check; +pub mod unified_authentication_service; use api_models::payments::{AdditionalPaymentData, RequestSurchargeDetails}; use common_utils::{ consts, errors, 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 new file mode 100644 index 000000000000..cbca353b1009 --- /dev/null +++ b/crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs @@ -0,0 +1,58 @@ +use masking::Secret; + +#[derive(Clone, serde::Deserialize, Debug, serde::Serialize)] +pub struct UasPreAuthenticationRequestData { + pub service_details: Option, + pub transaction_details: Option, +} + +#[derive(Clone, serde::Deserialize, Debug, serde::Serialize)] +pub struct ServiceDetails { + pub service_session_ids: Option, +} + +#[derive(Clone, serde::Deserialize, Debug, serde::Serialize)] +pub struct ServiceSessionIds { + pub correlation_id: Option, + pub merchant_transaction_id: Option, + pub x_src_flow_id: Option, +} + +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)] +pub struct TransactionDetails { + pub amount: common_utils::types::MinorUnit, + pub currency: common_enums::Currency, +} + +#[derive(Clone, Debug)] +pub struct UasPostAuthenticationRequestData; + +#[derive(Debug, Clone)] +pub enum UasAuthenticationResponseData { + PreAuthentication {}, + PostAuthentication { + authentication_details: PostAuthenticationDetails, + }, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct PostAuthenticationDetails { + pub eci: Option, + pub token_details: TokenDetails, + pub dynamic_data_details: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct TokenDetails { + pub payment_token: cards::CardNumber, + pub payment_account_reference: String, + pub token_expiration_month: Secret, + pub token_expiration_year: Secret, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct DynamicData { + pub dynamic_data_value: Option>, + pub dynamic_data_type: String, + pub ds_trans_id: Option, +} diff --git a/crates/router/src/core.rs b/crates/router/src/core.rs index a2da33841962..f6fe1d85b5de 100644 --- a/crates/router/src/core.rs +++ b/crates/router/src/core.rs @@ -52,3 +52,5 @@ pub mod verification; #[cfg(feature = "olap")] pub mod verify_connector; pub mod webhooks; + +pub mod unified_authentication_service; diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index c4b35d527980..da6252d54292 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -190,6 +190,7 @@ pub fn construct_router_data( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type, }) } diff --git a/crates/router/src/core/fraud_check/flows/checkout_flow.rs b/crates/router/src/core/fraud_check/flows/checkout_flow.rs index 84ba1f26a5d1..b07268ae6668 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -161,6 +161,7 @@ impl ConstructFlowSpecificData( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) diff --git a/crates/router/src/core/fraud_check/flows/record_return.rs b/crates/router/src/core/fraud_check/flows/record_return.rs index 6e29d01c81fb..d05f7280024a 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -129,6 +129,7 @@ impl ConstructFlowSpecificData( current: &'a Op, ) -> BoxedOperation<'a, F, api::PaymentsRequest, PaymentData> where - F: Send + Clone, + F: Send + Clone + Sync, Op: Operation> + Send + Sync, &'a Op: Operation>, PaymentStatus: Operation>, 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 286680062f88..8725470e2599 100644 --- a/crates/router/src/core/payments/connector_integration_v2_impls.rs +++ b/crates/router/src/core/payments/connector_integration_v2_impls.rs @@ -2226,3 +2226,114 @@ default_imp_for_new_connector_integration_connector_authentication!( connector::Zsl, connector::Plaid ); + +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 + services::ConnectorIntegrationV2< + api::PreAuthenticate, + types::UasFlowData, + types::UasPreAuthenticationRequestData, + types::UasAuthenticationResponseData, + > for $path::$connector + {} + impl + services::ConnectorIntegrationV2< + api::PostAuthenticate, + types::UasFlowData, + types::UasPostAuthenticationRequestData, + types::UasAuthenticationResponseData, + > for $path::$connector + {} + )* + }; +} + +default_imp_for_new_connector_integration_uas!( + 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::Riskified, + connector::Signifyd, + connector::Square, + connector::Stax, + connector::Stripe, + connector::Shift4, + connector::Taxjar, + connector::Trustpay, + connector::Threedsecureio, + connector::Thunes, + connector::Tsys, + connector::Volt, + connector::Wellsfargo, + connector::Wise, + connector::Worldline, + connector::Worldpay, + connector::Zen, + connector::Zsl, + connector::Plaid +); diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 00001e0e6c02..9ce0ccb4496a 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -2610,6 +2610,232 @@ default_imp_for_post_session_tokens!( connector::Wise ); +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 + services::ConnectorIntegration< + api::PreAuthenticate, + types::UasPreAuthenticationRequestData, + types::UasAuthenticationResponseData + > for $path::$connector + {} + )* + }; +} +#[cfg(feature = "dummy_connector")] +impl api::UasPreAuthentication for connector::DummyConnector {} +#[cfg(feature = "dummy_connector")] +impl api::UnifiedAuthenticationService for connector::DummyConnector {} +#[cfg(feature = "dummy_connector")] +impl + services::ConnectorIntegration< + api::PreAuthenticate, + types::UasPreAuthenticationRequestData, + types::UasAuthenticationResponseData, + > for connector::DummyConnector +{ +} + +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 +); + +macro_rules! default_imp_for_uas_post_authentication { + ($($path:ident::$connector:ident),*) => { + $( impl api::UasPostAuthentication for $path::$connector {} + impl + services::ConnectorIntegration< + api::PostAuthenticate, + types::UasPostAuthenticationRequestData, + types::UasAuthenticationResponseData + > for $path::$connector + {} + )* + }; +} +#[cfg(feature = "dummy_connector")] +impl api::UasPostAuthentication for connector::DummyConnector {} +#[cfg(feature = "dummy_connector")] +impl + services::ConnectorIntegration< + api::PostAuthenticate, + types::UasPostAuthenticationRequestData, + types::UasAuthenticationResponseData, + > for connector::DummyConnector +{ +} + +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 +); /// 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 /// based on various payment parameters. It's primarily used in two-step (auth + capture) payment flows for CaptureMethod SequentialAutomatic diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 61b47df3256f..6265ac3f1858 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -3964,6 +3964,7 @@ pub fn router_data_type_conversion( additional_merchant_data: router_data.additional_merchant_data, header_payload: router_data.header_payload, connector_mandate_request_reference_id: router_data.connector_mandate_request_reference_id, + authentication_id: router_data.authentication_id, psd2_sca_exemption_type: router_data.psd2_sca_exemption_type, } } diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index f957b939acfe..a7e60274d135 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -295,6 +295,18 @@ pub trait Domain: Send + Sync { Ok(()) } + async fn call_unified_authentication_service_if_eligible<'a>( + &'a self, + _state: &SessionState, + _payment_data: &mut D, + _should_continue_confirm_transaction: &mut bool, + _connector_call_type: &ConnectorCallType, + _merchant_account: &domain::Profile, + _key_store: &domain::MerchantKeyStore, + ) -> CustomResult<(), errors::ApiErrorResponse> { + Ok(()) + } + #[allow(clippy::too_many_arguments)] async fn payments_dynamic_tax_calculation<'a>( &'a self, diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index 97832a081846..b3d2985bf803 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -32,7 +32,7 @@ type PaymentApproveOperation<'a, F> = BoxedOperation<'a, F, api::PaymentsCaptureRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsCaptureRequest> +impl GetTracker, api::PaymentsCaptureRequest> for PaymentApprove { #[instrument(skip_all)] @@ -209,7 +209,9 @@ impl GetTracker, api::PaymentsCaptureRequest> } #[async_trait] -impl UpdateTracker, api::PaymentsCaptureRequest> for PaymentApprove { +impl UpdateTracker, api::PaymentsCaptureRequest> + for PaymentApprove +{ #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -268,7 +270,7 @@ impl UpdateTracker, api::PaymentsCaptureRequest> for } } -impl ValidateRequest> +impl ValidateRequest> for PaymentApprove { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index ef6570abf8c1..a40ecf0242e7 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -33,7 +33,9 @@ type PaymentCancelOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsCancelRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsCancelRequest> for PaymentCancel { +impl GetTracker, api::PaymentsCancelRequest> + for PaymentCancel +{ #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -218,7 +220,9 @@ impl GetTracker, api::PaymentsCancelRequest> } #[async_trait] -impl UpdateTracker, api::PaymentsCancelRequest> for PaymentCancel { +impl UpdateTracker, api::PaymentsCancelRequest> + for PaymentCancel +{ #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -286,7 +290,7 @@ impl UpdateTracker, api::PaymentsCancelRequest> for } } -impl ValidateRequest> +impl ValidateRequest> for PaymentCancel { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 2451cbcd8e9d..d9068b402ce8 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -32,7 +32,7 @@ type PaymentCaptureOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsCaptureRequest, payments::PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsCaptureRequest> +impl GetTracker, api::PaymentsCaptureRequest> for PaymentCapture { #[instrument(skip_all)] @@ -269,7 +269,7 @@ impl GetTracker, api::PaymentsCaptu } #[async_trait] -impl UpdateTracker, api::PaymentsCaptureRequest> +impl UpdateTracker, api::PaymentsCaptureRequest> for PaymentCapture { #[instrument(skip_all)] @@ -326,8 +326,8 @@ impl UpdateTracker, api::PaymentsCaptureRe } } -impl ValidateRequest> - for PaymentCapture +impl + ValidateRequest> for PaymentCapture { #[instrument(skip_all)] fn validate_request<'a, 'b>( 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 b296d6c3052c..f4f5813c1b04 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -35,7 +35,9 @@ type CompleteAuthorizeOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsRequest> for CompleteAuthorize { +impl GetTracker, api::PaymentsRequest> + for CompleteAuthorize +{ #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -369,7 +371,7 @@ impl GetTracker, api::PaymentsRequest> for Co } #[async_trait] -impl Domain> for CompleteAuthorize { +impl Domain> for CompleteAuthorize { #[instrument(skip_all)] async fn get_or_create_customer_details<'a>( &'a self, @@ -458,7 +460,7 @@ impl Domain> for Comple } #[async_trait] -impl UpdateTracker, api::PaymentsRequest> for CompleteAuthorize { +impl UpdateTracker, api::PaymentsRequest> for CompleteAuthorize { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -504,7 +506,7 @@ impl UpdateTracker, api::PaymentsRequest> for Comple } } -impl ValidateRequest> +impl ValidateRequest> for CompleteAuthorize { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 67829f1fb732..c3fe518ff5eb 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -38,6 +38,10 @@ use crate::{ self, helpers, operations, populate_surcharge_details, CustomerDetails, PaymentAddress, PaymentData, }, + unified_authentication_service::{ + self, + types::{ClickToPay, UnifiedAuthenticationService, CTP_MASTERCARD}, + }, utils as core_utils, }, routes::{app::ReqState, SessionState}, @@ -59,7 +63,9 @@ pub struct PaymentConfirm; type PaymentConfirmOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsRequest> for PaymentConfirm { +impl GetTracker, api::PaymentsRequest> + for PaymentConfirm +{ #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -827,7 +833,7 @@ impl GetTracker, api::PaymentsRequest> for Pa } #[async_trait] -impl Domain> for PaymentConfirm { +impl Domain> for PaymentConfirm { #[instrument(skip_all)] async fn get_or_create_customer_details<'a>( &'a self, @@ -1027,6 +1033,93 @@ impl Domain> for Paymen Ok(()) } + #[allow(clippy::too_many_arguments)] + async fn call_unified_authentication_service_if_eligible<'a>( + &'a self, + state: &SessionState, + payment_data: &mut PaymentData, + _should_continue_confirm_transaction: &mut bool, + _connector_call_type: &ConnectorCallType, + 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 { + 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, + &business_profile.merchant_id, + None, + key_store, + business_profile.get_id(), + connector_name, + None, + ) + .await?; + + let authentication_id = + common_utils::generate_id_with_default_len(consts::AUTHENTICATION_ID_PREFIX); + + let payment_method = payment_data.payment_attempt.payment_method.ok_or( + errors::ApiErrorResponse::MissingRequiredField { + field_name: "payment_method", + }, + )?; + + let connector_transaction_id = connector_mca + .clone() + .get_mca_id() + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "Error while finding mca_id from merchant_connector_account", + )?; + + ClickToPay::pre_authentication( + state, + key_store, + business_profile, + payment_data, + &connector_mca, + connector_name, + &authentication_id, + payment_method, + ) + .await?; + + payment_data.payment_attempt.authentication_id = Some(authentication_id.clone()); + + let network_token = ClickToPay::post_authentication( + state, + key_store, + business_profile, + payment_data, + &connector_mca, + connector_name, + payment_method, + ) + .await?; + + payment_data.payment_method_data = + network_token.map(domain::PaymentMethodData::NetworkToken); + + unified_authentication_service::create_new_authentication( + state, + payment_data.payment_attempt.merchant_id.clone(), + connector_name.to_string(), + business_profile.get_id().clone(), + Some(payment_data.payment_intent.get_id().clone()), + connector_transaction_id, + &authentication_id, + ) + .await?; + } + } + + Ok(()) + } + #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, @@ -1111,7 +1204,7 @@ impl Domain> for Paymen #[cfg(all(feature = "v2", feature = "customer_v2"))] #[async_trait] -impl UpdateTracker, api::PaymentsRequest> for PaymentConfirm { +impl UpdateTracker, api::PaymentsRequest> for PaymentConfirm { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -1137,7 +1230,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] #[async_trait] -impl UpdateTracker, api::PaymentsRequest> for PaymentConfirm { +impl UpdateTracker, api::PaymentsRequest> for PaymentConfirm { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -1540,7 +1633,9 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen } } -impl ValidateRequest> for PaymentConfirm { +impl ValidateRequest> + for PaymentConfirm +{ #[instrument(skip_all)] fn validate_request<'a, 'b>( &'b self, diff --git a/crates/router/src/core/payments/operations/payment_confirm_intent.rs b/crates/router/src/core/payments/operations/payment_confirm_intent.rs index 05c901025655..f6c47de37623 100644 --- a/crates/router/src/core/payments/operations/payment_confirm_intent.rs +++ b/crates/router/src/core/payments/operations/payment_confirm_intent.rs @@ -71,7 +71,7 @@ type BoxedConfirmOperation<'b, F> = // TODO: change the macro to include changes for v2 // TODO: PaymentData in the macro should be an input -impl Operation for &PaymentIntentConfirm { +impl Operation for &PaymentIntentConfirm { type Data = PaymentConfirmData; fn to_validate_request( &self, @@ -99,7 +99,7 @@ impl Operation for &PaymentInt } } #[automatically_derived] -impl Operation for PaymentIntentConfirm { +impl Operation for PaymentIntentConfirm { type Data = PaymentConfirmData; fn to_validate_request( &self, @@ -125,7 +125,7 @@ impl Operation for PaymentInte } } -impl ValidateRequest> +impl ValidateRequest> for PaymentIntentConfirm { #[instrument(skip_all)] @@ -145,7 +145,7 @@ impl ValidateRequest GetTracker, PaymentsConfirmIntentRequest> +impl GetTracker, PaymentsConfirmIntentRequest> for PaymentIntentConfirm { #[instrument(skip_all)] @@ -259,7 +259,7 @@ impl GetTracker, PaymentsConfirmIntent } #[async_trait] -impl Domain> +impl Domain> for PaymentIntentConfirm { async fn get_customer_details<'a>( @@ -348,7 +348,7 @@ impl Domain UpdateTracker, PaymentsConfirmIntentRequest> +impl UpdateTracker, PaymentsConfirmIntentRequest> for PaymentIntentConfirm { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 3bd5b9abcdde..6b9a4a76711e 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -67,7 +67,7 @@ type PaymentCreateOperation<'a, F> = BoxedOperation<'a, F, api::PaymentsRequest, /// The `get_trackers` function for `PaymentsCreate` is an entrypoint for new payments /// This will create all the entities required for a new payment from the request #[async_trait] -impl GetTracker, api::PaymentsRequest> for PaymentCreate { +impl GetTracker, api::PaymentsRequest> for PaymentCreate { #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -628,7 +628,7 @@ impl GetTracker, api::PaymentsRequest> for Pa } #[async_trait] -impl Domain> for PaymentCreate { +impl Domain> for PaymentCreate { #[instrument(skip_all)] async fn get_or_create_customer_details<'a>( &'a self, @@ -816,7 +816,7 @@ impl Domain> for Paymen } #[async_trait] -impl UpdateTracker, api::PaymentsRequest> for PaymentCreate { +impl UpdateTracker, api::PaymentsRequest> for PaymentCreate { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -940,7 +940,9 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen } } -impl ValidateRequest> for PaymentCreate { +impl ValidateRequest> + for PaymentCreate +{ #[instrument(skip_all)] fn validate_request<'a, 'b>( &'b self, diff --git a/crates/router/src/core/payments/operations/payment_create_intent.rs b/crates/router/src/core/payments/operations/payment_create_intent.rs index 988e040f3769..372d106eb924 100644 --- a/crates/router/src/core/payments/operations/payment_create_intent.rs +++ b/crates/router/src/core/payments/operations/payment_create_intent.rs @@ -29,7 +29,7 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub struct PaymentIntentCreate; -impl Operation for &PaymentIntentCreate { +impl Operation for &PaymentIntentCreate { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -55,7 +55,7 @@ impl Operation for &PaymentInte } } -impl Operation for PaymentIntentCreate { +impl Operation for PaymentIntentCreate { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -85,7 +85,8 @@ type PaymentsCreateIntentOperation<'b, F> = BoxedOperation<'b, F, PaymentsCreateIntentRequest, payments::PaymentIntentData>; #[async_trait] -impl GetTracker, PaymentsCreateIntentRequest> +impl + GetTracker, PaymentsCreateIntentRequest> for PaymentIntentCreate { #[instrument(skip_all)] @@ -168,7 +169,7 @@ impl GetTracker, PaymentsCrea } #[async_trait] -impl UpdateTracker, PaymentsCreateIntentRequest> +impl UpdateTracker, PaymentsCreateIntentRequest> for PaymentIntentCreate { #[instrument(skip_all)] @@ -213,7 +214,7 @@ impl } #[async_trait] -impl Domain> +impl Domain> for PaymentIntentCreate { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs index f66186c7c571..14eb9c2d8b11 100644 --- a/crates/router/src/core/payments/operations/payment_get.rs +++ b/crates/router/src/core/payments/operations/payment_get.rs @@ -53,7 +53,7 @@ type BoxedConfirmOperation<'b, F> = // TODO: change the macro to include changes for v2 // TODO: PaymentData in the macro should be an input -impl Operation for &PaymentGet { +impl Operation for &PaymentGet { type Data = PaymentStatusData; fn to_validate_request( &self, @@ -77,7 +77,7 @@ impl Operation for &PaymentGet { } } #[automatically_derived] -impl Operation for PaymentGet { +impl Operation for PaymentGet { type Data = PaymentStatusData; fn to_validate_request( &self, @@ -101,7 +101,7 @@ impl Operation for PaymentGet { } } -impl ValidateRequest> +impl ValidateRequest> for PaymentGet { #[instrument(skip_all)] @@ -121,7 +121,9 @@ impl ValidateRequest GetTracker, PaymentsRetrieveRequest> for PaymentGet { +impl GetTracker, PaymentsRetrieveRequest> + for PaymentGet +{ #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -196,7 +198,9 @@ impl GetTracker, PaymentsRetrieveReques } #[async_trait] -impl Domain> for PaymentGet { +impl Domain> + for PaymentGet +{ async fn get_customer_details<'a>( &'a self, state: &SessionState, @@ -284,7 +288,9 @@ impl Domain> f } #[async_trait] -impl UpdateTracker, PaymentsRetrieveRequest> for PaymentGet { +impl UpdateTracker, PaymentsRetrieveRequest> + for PaymentGet +{ #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, diff --git a/crates/router/src/core/payments/operations/payment_get_intent.rs b/crates/router/src/core/payments/operations/payment_get_intent.rs index 344f10434bdd..16b44436c18f 100644 --- a/crates/router/src/core/payments/operations/payment_get_intent.rs +++ b/crates/router/src/core/payments/operations/payment_get_intent.rs @@ -22,7 +22,7 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub struct PaymentGetIntent; -impl Operation for &PaymentGetIntent { +impl Operation for &PaymentGetIntent { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -47,7 +47,7 @@ impl Operation for &PaymentGetInte } } -impl Operation for PaymentGetIntent { +impl Operation for PaymentGetIntent { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -76,7 +76,7 @@ type PaymentsGetIntentOperation<'b, F> = BoxedOperation<'b, F, PaymentsGetIntentRequest, payments::PaymentIntentData>; #[async_trait] -impl GetTracker, PaymentsGetIntentRequest> +impl GetTracker, PaymentsGetIntentRequest> for PaymentGetIntent { #[instrument(skip_all)] @@ -111,7 +111,7 @@ impl GetTracker, PaymentsGetI } #[async_trait] -impl UpdateTracker, PaymentsGetIntentRequest> +impl UpdateTracker, PaymentsGetIntentRequest> for PaymentGetIntent { #[instrument(skip_all)] @@ -137,7 +137,8 @@ impl UpdateTracker, PaymentsGetInten } } -impl ValidateRequest> +impl + ValidateRequest> for PaymentGetIntent { #[instrument(skip_all)] @@ -155,7 +156,7 @@ impl ValidateRequest Domain> +impl Domain> for PaymentGetIntent { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs index 846f739e0823..7c30d9c5b759 100644 --- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs +++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs @@ -32,7 +32,7 @@ type PaymentPostSessionTokensOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsPostSessionTokensRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsPostSessionTokensRequest> +impl GetTracker, api::PaymentsPostSessionTokensRequest> for PaymentPostSessionTokens { #[instrument(skip_all)] @@ -179,7 +179,7 @@ impl GetTracker, api::PaymentsPostSessionToke } #[async_trait] -impl Domain> +impl Domain> for PaymentPostSessionTokens { #[instrument(skip_all)] @@ -241,7 +241,7 @@ impl Domain UpdateTracker, api::PaymentsPostSessionTokensRequest> +impl UpdateTracker, api::PaymentsPostSessionTokensRequest> for PaymentPostSessionTokens { #[instrument(skip_all)] @@ -264,7 +264,8 @@ impl UpdateTracker, api::PaymentsPostSessionTokensRe } } -impl ValidateRequest> +impl + ValidateRequest> for PaymentPostSessionTokens { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index c747c7d984a8..df9544dfb486 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -30,7 +30,9 @@ pub struct PaymentReject; type PaymentRejectOperation<'b, F> = BoxedOperation<'b, F, PaymentsCancelRequest, PaymentData>; #[async_trait] -impl GetTracker, PaymentsCancelRequest> for PaymentReject { +impl GetTracker, PaymentsCancelRequest> + for PaymentReject +{ #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -205,7 +207,7 @@ impl GetTracker, PaymentsCancelRequest> for P } #[async_trait] -impl UpdateTracker, PaymentsCancelRequest> for PaymentReject { +impl UpdateTracker, PaymentsCancelRequest> for PaymentReject { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -280,7 +282,9 @@ impl UpdateTracker, PaymentsCancelRequest> for Payme } } -impl ValidateRequest> for PaymentReject { +impl ValidateRequest> + for PaymentReject +{ #[instrument(skip_all)] fn validate_request<'a, 'b>( &'b self, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index ebc663aaf395..a9a64c688094 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -31,7 +31,7 @@ type PaymentSessionOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsSessionRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsSessionRequest> +impl GetTracker, api::PaymentsSessionRequest> for PaymentSession { #[instrument(skip_all)] @@ -227,7 +227,9 @@ impl GetTracker, api::PaymentsSessionRequest> } #[async_trait] -impl UpdateTracker, api::PaymentsSessionRequest> for PaymentSession { +impl UpdateTracker, api::PaymentsSessionRequest> + for PaymentSession +{ #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -267,7 +269,7 @@ impl UpdateTracker, api::PaymentsSessionRequest> for } } -impl ValidateRequest> +impl ValidateRequest> for PaymentSession { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_session_intent.rs b/crates/router/src/core/payments/operations/payment_session_intent.rs index ee490408cb11..6072681c2ff0 100644 --- a/crates/router/src/core/payments/operations/payment_session_intent.rs +++ b/crates/router/src/core/payments/operations/payment_session_intent.rs @@ -48,7 +48,7 @@ impl ValidateStatusForOperation for PaymentSessionIntent { } } -impl Operation for &PaymentSessionIntent { +impl Operation for &PaymentSessionIntent { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -66,7 +66,7 @@ impl Operation for &PaymentSessionIn } } -impl Operation for PaymentSessionIntent { +impl Operation for PaymentSessionIntent { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -88,7 +88,7 @@ type PaymentsCreateIntentOperation<'b, F> = BoxedOperation<'b, F, PaymentsSessionRequest, payments::PaymentIntentData>; #[async_trait] -impl GetTracker, PaymentsSessionRequest> +impl GetTracker, PaymentsSessionRequest> for PaymentSessionIntent { #[instrument(skip_all)] @@ -131,7 +131,8 @@ impl GetTracker, PaymentsSess } } -impl ValidateRequest> +impl + ValidateRequest> for PaymentSessionIntent { #[instrument(skip_all)] @@ -149,7 +150,7 @@ impl ValidateRequest Domain> +impl Domain> for PaymentSessionIntent { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index edcb0282bdd3..3285914affae 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -30,7 +30,9 @@ type PaymentSessionOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsStartRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsStartRequest> for PaymentStart { +impl GetTracker, api::PaymentsStartRequest> + for PaymentStart +{ #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -212,7 +214,7 @@ impl GetTracker, api::PaymentsStartRequest> f } #[async_trait] -impl UpdateTracker, api::PaymentsStartRequest> for PaymentStart { +impl UpdateTracker, api::PaymentsStartRequest> for PaymentStart { #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, @@ -233,7 +235,7 @@ impl UpdateTracker, api::PaymentsStartRequest> for P } } -impl ValidateRequest> +impl ValidateRequest> for PaymentStart { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index ab3a70aa1bb4..e2c9a4d7a3ba 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -31,7 +31,7 @@ pub struct PaymentStatus; type PaymentStatusOperation<'b, F, R> = BoxedOperation<'b, F, R, PaymentData>; -impl Operation for PaymentStatus { +impl Operation for PaymentStatus { type Data = PaymentData; fn to_domain(&self) -> RouterResult<&dyn Domain>> { Ok(self) @@ -43,7 +43,7 @@ impl Operation for PaymentStatus { Ok(self) } } -impl Operation for &PaymentStatus { +impl Operation for &PaymentStatus { type Data = PaymentData; fn to_domain(&self) -> RouterResult<&dyn Domain>> { Ok(*self) @@ -57,7 +57,7 @@ impl Operation for &PaymentStatus { } #[async_trait] -impl Domain> for PaymentStatus { +impl Domain> for PaymentStatus { #[instrument(skip_all)] async fn get_or_create_customer_details<'a>( &'a self, @@ -137,7 +137,7 @@ impl Domain> for Paymen } #[async_trait] -impl UpdateTracker, api::PaymentsRequest> for PaymentStatus { +impl UpdateTracker, api::PaymentsRequest> for PaymentStatus { async fn update_trackers<'b>( &'b self, _state: &'b SessionState, @@ -161,7 +161,9 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen } #[async_trait] -impl UpdateTracker, api::PaymentsRetrieveRequest> for PaymentStatus { +impl UpdateTracker, api::PaymentsRetrieveRequest> + for PaymentStatus +{ async fn update_trackers<'b>( &'b self, _state: &'b SessionState, @@ -185,7 +187,7 @@ impl UpdateTracker, api::PaymentsRetrieveRequest> fo } #[async_trait] -impl GetTracker, api::PaymentsRetrieveRequest> +impl GetTracker, api::PaymentsRetrieveRequest> for PaymentStatus { #[instrument(skip_all)] @@ -519,7 +521,7 @@ async fn get_tracker_for_sync< Ok(get_trackers_response) } -impl ValidateRequest> +impl ValidateRequest> for PaymentStatus { fn validate_request<'b>( diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 61a52e7dfb58..1fba79968b68 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -45,7 +45,7 @@ pub struct PaymentUpdate; type PaymentUpdateOperation<'a, F> = BoxedOperation<'a, F, api::PaymentsRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsRequest> for PaymentUpdate { +impl GetTracker, api::PaymentsRequest> for PaymentUpdate { #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, @@ -505,7 +505,7 @@ impl GetTracker, api::PaymentsRequest> for Pa } #[async_trait] -impl Domain> for PaymentUpdate { +impl Domain> for PaymentUpdate { #[instrument(skip_all)] async fn get_or_create_customer_details<'a>( &'a self, @@ -692,7 +692,7 @@ impl Domain> for Paymen } #[async_trait] -impl UpdateTracker, api::PaymentsRequest> for PaymentUpdate { +impl UpdateTracker, api::PaymentsRequest> for PaymentUpdate { #[cfg(all(feature = "v2", feature = "customer_v2"))] #[instrument(skip_all)] async fn update_trackers<'b>( @@ -955,7 +955,9 @@ impl ForeignTryFrom for CustomerData { } } -impl ValidateRequest> for PaymentUpdate { +impl ValidateRequest> + for PaymentUpdate +{ #[instrument(skip_all)] fn validate_request<'a, 'b>( &'b self, diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 1b7acc796ec5..a629938936b6 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -34,7 +34,7 @@ type PaymentIncrementalAuthorizationOperation<'b, F> = BoxedOperation<'b, F, PaymentsIncrementalAuthorizationRequest, payments::PaymentData>; #[async_trait] -impl +impl GetTracker, PaymentsIncrementalAuthorizationRequest> for PaymentIncrementalAuthorization { @@ -186,7 +186,8 @@ impl } #[async_trait] -impl UpdateTracker, PaymentsIncrementalAuthorizationRequest> +impl + UpdateTracker, PaymentsIncrementalAuthorizationRequest> for PaymentIncrementalAuthorization { #[instrument(skip_all)] @@ -278,7 +279,7 @@ impl UpdateTracker, PaymentsIncrementalAut } } -impl +impl ValidateRequest> for PaymentIncrementalAuthorization { @@ -304,7 +305,8 @@ impl } #[async_trait] -impl Domain> +impl + Domain> for PaymentIncrementalAuthorization { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs index 712dff35c7a1..dbfed35a44fa 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -36,7 +36,8 @@ type PaymentSessionUpdateOperation<'b, F> = BoxedOperation<'b, F, api::PaymentsDynamicTaxCalculationRequest, PaymentData>; #[async_trait] -impl GetTracker, api::PaymentsDynamicTaxCalculationRequest> +impl + GetTracker, api::PaymentsDynamicTaxCalculationRequest> for PaymentSessionUpdate { #[instrument(skip_all)] @@ -192,7 +193,7 @@ impl GetTracker, api::PaymentsDynamicTaxCalcu } #[async_trait] -impl Domain> +impl Domain> for PaymentSessionUpdate { #[instrument(skip_all)] @@ -364,7 +365,7 @@ impl Domain UpdateTracker, api::PaymentsDynamicTaxCalculationRequest> +impl UpdateTracker, api::PaymentsDynamicTaxCalculationRequest> for PaymentSessionUpdate { #[instrument(skip_all)] @@ -442,7 +443,8 @@ impl UpdateTracker, api::PaymentsDynamicTaxCalculati } } -impl ValidateRequest> +impl + ValidateRequest> for PaymentSessionUpdate { #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 0f248d6cc36c..1a635b097ef3 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -167,6 +167,7 @@ where additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) @@ -370,6 +371,7 @@ pub async fn construct_payment_router_data_for_authorize<'a>( additional_merchant_data: None, header_payload, connector_mandate_request_reference_id, + authentication_id: None, psd2_sca_exemption_type: None, }; @@ -503,6 +505,7 @@ pub async fn construct_router_data_for_psync<'a>( additional_merchant_data: None, header_payload, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; @@ -650,6 +653,7 @@ pub async fn construct_payment_router_data_for_sdk_session<'a>( header_payload, connector_mandate_request_reference_id: None, psd2_sca_exemption_type: None, + authentication_id: None, }; Ok(router_data) @@ -847,6 +851,7 @@ where }), header_payload, connector_mandate_request_reference_id, + authentication_id: None, psd2_sca_exemption_type: payment_data.payment_intent.psd2_sca_exemption_type, }; diff --git a/crates/router/src/core/unified_authentication_service.rs b/crates/router/src/core/unified_authentication_service.rs new file mode 100644 index 000000000000..bd08ea7fe6b7 --- /dev/null +++ b/crates/router/src/core/unified_authentication_service.rs @@ -0,0 +1,187 @@ +pub mod transformers; +pub mod types; +pub mod utils; + +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, + }, +}; + +use super::{errors::RouterResult, payments::helpers::MerchantConnectorAccountType}; +use crate::{ + core::{ + errors::utils::StorageErrorExt, + payments::PaymentData, + unified_authentication_service::types::{ + ClickToPay, UnifiedAuthenticationService, UNIFIED_AUTHENTICATION_SERVICE, + }, + }, + db::domain, + routes::SessionState, + types::api, +}; + +#[cfg(feature = "v1")] +#[async_trait::async_trait] +impl UnifiedAuthenticationService for ClickToPay { + async fn pre_authentication( + state: &SessionState, + _key_store: &domain::MerchantKeyStore, + _business_profile: &domain::Profile, + payment_data: &PaymentData, + merchant_connector_account: &MerchantConnectorAccountType, + connector_name: &str, + authentication_id: &str, + payment_method: common_enums::PaymentMethod, + ) -> RouterResult<()> { + 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( + connector_name.to_string(), + payment_method, + payment_data.payment_attempt.merchant_id.clone(), + None, + pre_authentication_data, + merchant_connector_account, + Some(authentication_id.to_owned()), + )?; + + utils::do_auth_connector_call( + state, + UNIFIED_AUTHENTICATION_SERVICE.to_string(), + pre_auth_router_data, + ) + .await?; + + Ok(()) + } + + async fn post_authentication( + state: &SessionState, + _key_store: &domain::MerchantKeyStore, + _business_profile: &domain::Profile, + payment_data: &PaymentData, + merchant_connector_account: &MerchantConnectorAccountType, + connector_name: &str, + payment_method: common_enums::PaymentMethod, + ) -> RouterResult> + { + let post_authentication_data = UasPostAuthenticationRequestData; + let authentication_id = payment_data + .payment_attempt + .authentication_id + .clone() + .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( + connector_name.to_string(), + payment_method, + payment_data.payment_attempt.merchant_id.clone(), + None, + post_authentication_data, + merchant_connector_account, + Some(authentication_id.clone()), + )?; + + let response = utils::do_auth_connector_call( + state, + UNIFIED_AUTHENTICATION_SERVICE.to_string(), + post_auth_router_data, + ) + .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) + } + + fn confirmation( + _state: &SessionState, + _key_store: &domain::MerchantKeyStore, + _business_profile: &domain::Profile, + _merchant_connector_account: &MerchantConnectorAccountType, + ) -> RouterResult<()> { + Ok(()) + } +} + +pub async fn create_new_authentication( + state: &SessionState, + merchant_id: common_utils::id_type::MerchantId, + authentication_connector: String, + profile_id: common_utils::id_type::ProfileId, + payment_id: Option, + merchant_connector_id: common_utils::id_type::MerchantConnectorAccountId, + authentication_id: &str, +) -> RouterResult { + let new_authorization = AuthenticationNew { + authentication_id: authentication_id.to_owned(), + merchant_id, + authentication_connector, + connector_authentication_id: None, + payment_method_id: "".to_string(), + authentication_type: None, + authentication_status: common_enums::AuthenticationStatus::Started, + authentication_lifecycle_status: common_enums::AuthenticationLifecycleStatus::Unused, + error_message: None, + error_code: None, + connector_metadata: None, + maximum_supported_version: None, + threeds_server_transaction_id: None, + cavv: None, + authentication_flow_type: None, + message_version: None, + eci: None, + trans_status: None, + acquirer_bin: None, + acquirer_merchant_id: None, + three_ds_method_data: None, + three_ds_method_url: None, + acs_url: None, + challenge_request: None, + acs_reference_number: None, + acs_trans_id: None, + acs_signed_content: None, + profile_id, + payment_id, + merchant_connector_id, + ds_trans_id: None, + directory_server_id: None, + acquirer_country_code: None, + }; + state + .store + .insert_authentication(new_authorization) + .await + .to_duplicate_response(ApiErrorResponse::GenericDuplicateError { + message: format!( + "Authentication with authentication_id {} already exists", + authentication_id + ), + }) +} diff --git a/crates/router/src/core/unified_authentication_service/transformers.rs b/crates/router/src/core/unified_authentication_service/transformers.rs new file mode 100644 index 000000000000..cf3cb6f1f631 --- /dev/null +++ b/crates/router/src/core/unified_authentication_service/transformers.rs @@ -0,0 +1,36 @@ +use error_stack::Report; +use hyperswitch_domain_models::{ + errors::api_error_response::ApiErrorResponse, + router_request_types::unified_authentication_service::{ + ServiceDetails, ServiceSessionIds, TransactionDetails, UasPreAuthenticationRequestData, + }, +}; + +use crate::core::payments::PaymentData; + +#[cfg(feature = "v1")] +impl TryFrom> for UasPreAuthenticationRequestData { + type Error = Report; + fn try_from(payment_data: PaymentData) -> Result { + let service_details = ServiceDetails { + service_session_ids: Some(ServiceSessionIds { + merchant_transaction_id: None, + correlation_id: None, + x_src_flow_id: None, + }), + }; + let currency = payment_data.payment_attempt.currency.ok_or( + ApiErrorResponse::MissingRequiredField { + field_name: "currency", + }, + )?; + + let amount = payment_data.payment_attempt.net_amount.get_order_amount(); + let transaction_details = TransactionDetails { amount, currency }; + + Ok(Self { + service_details: Some(service_details), + transaction_details: Some(transaction_details), + }) + } +} diff --git a/crates/router/src/core/unified_authentication_service/types.rs b/crates/router/src/core/unified_authentication_service/types.rs new file mode 100644 index 000000000000..6fc73ec6cd2b --- /dev/null +++ b/crates/router/src/core/unified_authentication_service/types.rs @@ -0,0 +1,52 @@ +use crate::{ + core::{ + errors::RouterResult, + payments::{helpers::MerchantConnectorAccountType, PaymentData}, + }, + db::domain, + routes::SessionState, +}; + +pub const CTP_MASTERCARD: &str = "ctp_mastercard"; + +pub const UNIFIED_AUTHENTICATION_SERVICE: &str = "unified_authentication_service"; + +pub const IRRELEVANT_ATTEMPT_ID_IN_AUTHENTICATION_FLOW: &str = + "irrelevant_attempt_id_in_AUTHENTICATION_flow"; + +pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_AUTHENTICATION_FLOW: &str = + "irrelevant_connector_request_reference_id_in_AUTHENTICATION_flow"; + +pub struct ClickToPay; + +#[async_trait::async_trait] +pub trait UnifiedAuthenticationService { + #[allow(clippy::too_many_arguments)] + async fn pre_authentication( + _state: &SessionState, + _key_store: &domain::MerchantKeyStore, + _business_profile: &domain::Profile, + _payment_data: &PaymentData, + _merchant_connector_account: &MerchantConnectorAccountType, + _connector_name: &str, + _authentication_id: &str, + _payment_method: common_enums::PaymentMethod, + ) -> RouterResult<()>; + + async fn post_authentication( + _state: &SessionState, + _key_store: &domain::MerchantKeyStore, + _business_profile: &domain::Profile, + _payment_data: &PaymentData, + _merchant_connector_account: &MerchantConnectorAccountType, + _connector_name: &str, + _payment_method: common_enums::PaymentMethod, + ) -> RouterResult>; + + fn confirmation( + _state: &SessionState, + _key_store: &domain::MerchantKeyStore, + _business_profile: &domain::Profile, + _merchant_connector_account: &MerchantConnectorAccountType, + ) -> RouterResult<()>; +} diff --git a/crates/router/src/core/unified_authentication_service/utils.rs b/crates/router/src/core/unified_authentication_service/utils.rs new file mode 100644 index 000000000000..e0d10251049a --- /dev/null +++ b/crates/router/src/core/unified_authentication_service/utils.rs @@ -0,0 +1,172 @@ +use std::marker::PhantomData; + +use common_enums::enums::PaymentMethod; +use common_utils::ext_traits::ValueExt; +use diesel_models::authentication::{Authentication, AuthenticationUpdate}; +use error_stack::ResultExt; +use hyperswitch_domain_models::{ + errors::api_error_response::ApiErrorResponse, + payment_address::PaymentAddress, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_data_v2::UasFlowData, + router_request_types::unified_authentication_service::UasAuthenticationResponseData, +}; +use masking::ExposeOptionInterface; + +use super::types::{ + IRRELEVANT_ATTEMPT_ID_IN_AUTHENTICATION_FLOW, + IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_AUTHENTICATION_FLOW, +}; +use crate::{ + core::{ + errors::{utils::ConnectorErrorExt, RouterResult}, + payments, + unified_authentication_service::MerchantConnectorAccountType, + }, + services::{self, execute_connector_processing_step}, + types::api, + SessionState, +}; + +pub async fn update_trackers( + state: &SessionState, + router_data: RouterData, + authentication: Authentication, +) -> RouterResult { + let authentication_update = match router_data.response { + Ok(response) => match response { + UasAuthenticationResponseData::PreAuthentication {} => { + AuthenticationUpdate::AuthenticationStatusUpdate { + trans_status: common_enums::TransactionStatus::InformationOnly, + authentication_status: common_enums::AuthenticationStatus::Pending, + } + } + UasAuthenticationResponseData::PostAuthentication { + authentication_details, + } => AuthenticationUpdate::PostAuthenticationUpdate { + authentication_status: common_enums::AuthenticationStatus::Success, + trans_status: common_enums::TransactionStatus::Success, + authentication_value: authentication_details + .dynamic_data_details + .and_then(|data| data.dynamic_data_value.expose_option()), + eci: authentication_details.eci, + }, + }, + Err(error) => AuthenticationUpdate::ErrorUpdate { + connector_authentication_id: error.connector_transaction_id, + authentication_status: common_enums::AuthenticationStatus::Failed, + error_message: error + .reason + .map(|reason| format!("message: {}, reason: {}", error.message, reason)) + .or(Some(error.message)), + error_code: Some(error.code), + }, + }; + + state + .store + .update_authentication_by_merchant_id_authentication_id( + authentication, + authentication_update, + ) + .await + .change_context(ApiErrorResponse::InternalServerError) + .attach_printable("Error while updating authentication for uas") +} + +pub async fn do_auth_connector_call( + state: &SessionState, + authentication_connector_name: String, + router_data: RouterData, +) -> RouterResult> +where + Req: std::fmt::Debug + Clone + 'static, + Res: std::fmt::Debug + Clone + 'static, + F: std::fmt::Debug + Clone + 'static, + dyn api::Connector + Sync: services::api::ConnectorIntegration, + dyn api::ConnectorV2 + Sync: services::api::ConnectorIntegrationV2, +{ + let connector_data = + api::AuthenticationConnectorData::get_connector_by_name(&authentication_connector_name)?; + let connector_integration: services::BoxedUnifiedAuthenticationServiceInterface = + connector_data.connector.get_connector_integration(); + let router_data = execute_connector_processing_step( + state, + connector_integration, + &router_data, + payments::CallConnectorAction::Trigger, + None, + ) + .await + .to_payment_failed_response()?; + Ok(router_data) +} + +pub fn construct_uas_router_data( + authentication_connector_name: String, + payment_method: PaymentMethod, + merchant_id: common_utils::id_type::MerchantId, + address: Option, + request_data: Req, + merchant_connector_account: &MerchantConnectorAccountType, + authentication_id: Option, +) -> RouterResult> { + let test_mode: Option = merchant_connector_account.is_test_mode_on(); + let auth_type: ConnectorAuthType = merchant_connector_account + .get_connector_account_details() + .parse_value("ConnectorAuthType") + .change_context(ApiErrorResponse::InternalServerError)?; + Ok(RouterData { + flow: PhantomData, + merchant_id, + customer_id: None, + connector_customer: None, + connector: authentication_connector_name, + payment_id: common_utils::id_type::PaymentId::get_irrelevant_id("authentication") + .get_string_repr() + .to_owned(), + attempt_id: IRRELEVANT_ATTEMPT_ID_IN_AUTHENTICATION_FLOW.to_owned(), + status: common_enums::AttemptStatus::default(), + payment_method, + connector_auth_type: auth_type, + description: None, + return_url: None, + address: address.unwrap_or_default(), + auth_type: common_enums::AuthenticationType::default(), + connector_meta_data: merchant_connector_account.get_metadata(), + connector_wallets_details: merchant_connector_account.get_connector_wallets_details(), + amount_captured: None, + minor_amount_captured: None, + access_token: None, + session_token: None, + reference_id: None, + payment_method_token: None, + recurring_mandate_payment_data: None, + preprocessing_id: None, + payment_method_balance: None, + connector_api_version: None, + request: request_data, + response: Err(ErrorResponse::default()), + connector_request_reference_id: + IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_AUTHENTICATION_FLOW.to_owned(), + #[cfg(feature = "payouts")] + payout_method_data: None, + #[cfg(feature = "payouts")] + quote_id: None, + test_mode, + connector_http_status_code: None, + external_latency: None, + apple_pay_flow: None, + frm_metadata: None, + dispute_id: None, + refund_id: None, + payment_method_status: None, + connector_response: None, + integrity_check: Ok(()), + additional_merchant_data: None, + header_payload: None, + connector_mandate_request_reference_id: None, + authentication_id, + psd2_sca_exemption_type: None, + }) +} diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 56e5bc2b0852..1f214f48ffd5 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -215,6 +215,7 @@ pub async fn construct_payout_router_data<'a, F>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; @@ -396,6 +397,7 @@ pub async fn construct_refund_router_data<'a, F>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; @@ -704,6 +706,7 @@ pub async fn construct_accept_dispute_router_data<'a>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) @@ -801,6 +804,7 @@ pub async fn construct_submit_evidence_router_data<'a>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) @@ -904,6 +908,7 @@ pub async fn construct_upload_file_router_data<'a>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) @@ -1027,6 +1032,7 @@ pub async fn construct_payments_dynamic_tax_calculation_router_data<'a, F: Clone additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) @@ -1127,6 +1133,7 @@ pub async fn construct_defend_dispute_router_data<'a>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) @@ -1221,6 +1228,7 @@ pub async fn construct_retrieve_file_router_data<'a>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) diff --git a/crates/router/src/core/webhooks/utils.rs b/crates/router/src/core/webhooks/utils.rs index f1e84b2226a7..f86ed910e46a 100644 --- a/crates/router/src/core/webhooks/utils.rs +++ b/crates/router/src/core/webhooks/utils.rs @@ -123,6 +123,7 @@ pub async fn construct_webhook_router_data<'a>( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, }; Ok(router_data) diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index cfff235856b3..f746aa28fd5f 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -103,6 +103,9 @@ pub type BoxedAccessTokenConnectorIntegrationInterface = pub type BoxedFilesConnectorIntegrationInterface = BoxedConnectorIntegrationInterface; +pub type BoxedUnifiedAuthenticationServiceInterface = + BoxedConnectorIntegrationInterface; + /// Handle the flow by interacting with connector module /// `connector_request` is applicable only in case if the `CallConnectorAction` is `Trigger` /// In other cases, It will be created if required, even if it is not passed diff --git a/crates/router/src/services/conversion_impls.rs b/crates/router/src/services/conversion_impls.rs index 6ac934cd2fd7..3902ef624da2 100644 --- a/crates/router/src/services/conversion_impls.rs +++ b/crates/router/src/services/conversion_impls.rs @@ -1,3 +1,4 @@ +use error_stack::ResultExt; #[cfg(feature = "frm")] use hyperswitch_domain_models::router_data_v2::flow_common_types::FrmFlowData; #[cfg(feature = "payouts")] @@ -8,7 +9,8 @@ use hyperswitch_domain_models::{ router_data_v2::{ flow_common_types::{ AccessTokenFlowData, DisputesFlowData, ExternalAuthenticationFlowData, FilesFlowData, - MandateRevokeFlowData, PaymentFlowData, RefundFlowData, WebhookSourceVerifyData, + MandateRevokeFlowData, PaymentFlowData, RefundFlowData, UasFlowData, + WebhookSourceVerifyData, }, RouterDataV2, }, @@ -77,6 +79,7 @@ fn get_default_router_data( additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, } } @@ -688,3 +691,47 @@ impl RouterDataConversion Ok(router_data) } } + +impl RouterDataConversion for UasFlowData { + fn from_old_router_data( + old_router_data: &RouterData, + ) -> errors::CustomResult, errors::ConnectorError> + where + Self: Sized, + { + let resource_common_data = Self { + authenticate_by: old_router_data.connector.clone(), + source_authentication_id: old_router_data + .authentication_id + .clone() + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "source_authentication_id", + }) + .attach_printable("missing authentication id for uas")?, + }; + Ok(RouterDataV2 { + flow: std::marker::PhantomData, + resource_common_data, + connector_auth_type: old_router_data.connector_auth_type.clone(), + request: old_router_data.request.clone(), + response: old_router_data.response.clone(), + }) + } + + fn to_old_router_data( + new_router_data: RouterDataV2, + ) -> errors::CustomResult, errors::ConnectorError> + where + Self: Sized, + { + let Self { + authenticate_by, + source_authentication_id, + } = new_router_data.resource_common_data; + let mut router_data = + get_default_router_data("uas", new_router_data.request, new_router_data.response); + router_data.connector = authenticate_by; + router_data.authentication_id = Some(source_authentication_id); + Ok(router_data) + } +} diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 9e7fc4e204f2..e3d5b7246a88 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -48,10 +48,14 @@ pub use hyperswitch_domain_models::{ }, router_data_v2::{ AccessTokenFlowData, DisputesFlowData, ExternalAuthenticationFlowData, FilesFlowData, - MandateRevokeFlowData, PaymentFlowData, RefundFlowData, RouterDataV2, + MandateRevokeFlowData, PaymentFlowData, RefundFlowData, RouterDataV2, UasFlowData, WebhookSourceVerifyData, }, router_request_types::{ + unified_authentication_service::{ + UasAuthenticationResponseData, UasPostAuthenticationRequestData, + UasPreAuthenticationRequestData, + }, AcceptDisputeRequestData, AccessTokenRequestData, AuthorizeSessionTokenData, BrowserInformation, ChargeRefunds, ChargeRefundsOptions, CompleteAuthorizeData, CompleteAuthorizeRedirectResponse, ConnectorCustomerData, DefendDisputeRequestData, @@ -952,6 +956,7 @@ impl ForeignFrom<(&RouterData, T2) connector_mandate_request_reference_id: data .connector_mandate_request_reference_id .clone(), + authentication_id: data.authentication_id.clone(), psd2_sca_exemption_type: data.psd2_sca_exemption_type, } } @@ -1015,10 +1020,11 @@ impl dispute_id: None, connector_response: data.connector_response.clone(), integrity_check: Ok(()), - additional_merchant_data: data.additional_merchant_data.clone(), header_payload: data.header_payload.clone(), - connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, + additional_merchant_data: data.additional_merchant_data.clone(), + connector_mandate_request_reference_id: None, } } } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 661c557e20c8..f542eece81f0 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -36,6 +36,9 @@ 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}; @@ -58,7 +61,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::*, - webhooks::*, + unified_authentication_service::*, webhooks::*, }; use super::transformers::ForeignTryFrom; use crate::{ @@ -106,6 +109,7 @@ pub trait Connector: + ConnectorMandateRevoke + ExternalAuthentication + TaxCalculation + + UnifiedAuthenticationService { } @@ -124,7 +128,8 @@ impl< + FraudCheck + ConnectorMandateRevoke + ExternalAuthentication - + TaxCalculation, + + TaxCalculation + + UnifiedAuthenticationService, > Connector for T { } @@ -144,6 +149,7 @@ pub trait ConnectorV2: + FraudCheckV2 + ConnectorMandateRevokeV2 + ExternalAuthenticationV2 + + UnifiedAuthenticationServiceV2 { } impl< @@ -160,7 +166,8 @@ impl< + ConnectorVerifyWebhookSourceV2 + FraudCheckV2 + ConnectorMandateRevokeV2 - + ExternalAuthenticationV2, + + ExternalAuthenticationV2 + + UnifiedAuthenticationServiceV2, > ConnectorV2 for T { } diff --git a/crates/router/src/types/api/unified_authentication_service.rs b/crates/router/src/types/api/unified_authentication_service.rs new file mode 100644 index 000000000000..97f698856fcc --- /dev/null +++ b/crates/router/src/types/api/unified_authentication_service.rs @@ -0,0 +1,59 @@ +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 new file mode 100644 index 000000000000..3de12b0bb9e5 --- /dev/null +++ b/crates/router/src/types/api/unified_authentication_service_v2.rs @@ -0,0 +1,35 @@ +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/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index c368a3fb37d0..d046a57678b6 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -118,6 +118,7 @@ impl VerifyConnectorData { additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, } } diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index 2d0272cfa7e6..e3fd2bc1ee9c 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -130,6 +130,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, } } @@ -201,6 +202,7 @@ fn construct_refund_router_data() -> types::RefundsRouterData { additional_merchant_data: None, header_payload: None, connector_mandate_request_reference_id: None, + authentication_id: None, psd2_sca_exemption_type: None, } } diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 18c171d58c57..19fb4a43720e 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -549,6 +549,7 @@ pub trait ConnectorActions: Connector { header_payload: None, connector_mandate_request_reference_id: None, psd2_sca_exemption_type: None, + authentication_id: None, } } diff --git a/crates/router_derive/src/macros/operation.rs b/crates/router_derive/src/macros/operation.rs index a096c236b2f2..995db7a6cece 100644 --- a/crates/router_derive/src/macros/operation.rs +++ b/crates/router_derive/src/macros/operation.rs @@ -44,7 +44,7 @@ impl Derives { let req_type = Conversion::get_req_type(self); quote! { #[automatically_derived] - impl Operation for #struct_name { + impl Operation for #struct_name { type Data = PaymentData; #(#fns)* } @@ -59,7 +59,7 @@ impl Derives { let req_type = Conversion::get_req_type(self); quote! { #[automatically_derived] - impl Operation for &#struct_name { + impl Operation for &#struct_name { type Data = PaymentData; #(#ref_fns)* } From 64ca944ec28c58b38eda21483e1056d2c631a511 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 00:22:25 +0000 Subject: [PATCH 18/51] chore(version): 2024.12.12.0 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3325b5029997..5b096a05c956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.12.12.0 + +### Features + +- **core:** Add uas framework support ([#6743](https://github.com/juspay/hyperswitch/pull/6743)) ([`9466ced`](https://github.com/juspay/hyperswitch/commit/9466ced89407f31963bb0eb7c762749e3713591a)) + +### Bug Fixes + +- **router:** Card network for co-badged card and update regex ([#6801](https://github.com/juspay/hyperswitch/pull/6801)) ([`cd20537`](https://github.com/juspay/hyperswitch/commit/cd205378c035780586f6b94e5c9e03466165a33b)) + +**Full Changelog:** [`2024.12.11.0...2024.12.12.0`](https://github.com/juspay/hyperswitch/compare/2024.12.11.0...2024.12.12.0) + +- - - + ## 2024.12.11.0 ### Features From da5c34a335043cb225ed0e4ee06cd75a83c92c4d Mon Sep 17 00:00:00 2001 From: spritianeja03 <146620839+spritianeja03@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:48:05 +0530 Subject: [PATCH 19/51] refactor(connector): Move connectors Datatrans, Paybox, Placetopay, Bluesnap from router crate to hyperswitch_connector crate (#6730) Co-authored-by: Spriti Aneja Co-authored-by: deepanshu-iiitu --- Cargo.lock | 2 + crates/common_utils/src/consts.rs | 4 + crates/hyperswitch_connectors/Cargo.toml | 2 + .../hyperswitch_connectors/src/connectors.rs | 17 +- .../src/connectors}/bluesnap.rs | 483 +++++++++--------- .../src/connectors}/bluesnap/transformers.rs | 358 +++++++------ .../src/connectors}/datatrans.rs | 309 ++++++----- .../src/connectors}/datatrans/transformers.rs | 157 +++--- .../src/connectors/gocardless/transformers.rs | 22 +- .../src/connectors}/paybox.rs | 358 +++++++------ .../src/connectors}/paybox/transformers.rs | 152 +++--- .../src/connectors}/placetopay.rs | 320 ++++++------ .../connectors}/placetopay/transformers.rs | 116 ++--- .../src/default_implementations.rs | 124 +++++ .../src/default_implementations_v2.rs | 88 ++++ crates/hyperswitch_connectors/src/types.rs | 6 +- crates/hyperswitch_connectors/src/utils.rs | 432 ++++++++++------ crates/router/src/connector.rs | 42 +- crates/router/src/consts.rs | 4 - .../connector_integration_v2_impls.rs | 92 ---- crates/router/src/core/payments/flows.rs | 124 ----- 21 files changed, 1628 insertions(+), 1584 deletions(-) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/bluesnap.rs (78%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/bluesnap/transformers.rs (75%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/datatrans.rs (69%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/datatrans/transformers.rs (75%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/paybox.rs (65%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/paybox/transformers.rs (90%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/placetopay.rs (67%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/placetopay/transformers.rs (81%) diff --git a/Cargo.lock b/Cargo.lock index c8d5fc4cecc4..134759944543 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3982,6 +3982,7 @@ dependencies = [ "cards", "common_enums", "common_utils", + "encoding_rs", "error-stack", "hex", "http 0.2.12", @@ -4001,6 +4002,7 @@ dependencies = [ "roxmltree", "serde", "serde_json", + "serde_qs", "serde_urlencoded", "serde_with", "strum 0.26.3", diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index e430d59e54dd..39e5483700a5 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -142,3 +142,7 @@ pub const PUBLISHABLE_KEY_LENGTH: u16 = 39; /// The number of bytes allocated for the hashed connector transaction ID. /// Total number of characters equals CONNECTOR_TRANSACTION_ID_HASH_BYTES times 2. pub const CONNECTOR_TRANSACTION_ID_HASH_BYTES: usize = 25; + +/// Apple Pay validation url +pub const APPLEPAY_VALIDATION_URL: &str = + "https://apple-pay-gateway-cert.apple.com/paymentservices/startSession"; diff --git a/crates/hyperswitch_connectors/Cargo.toml b/crates/hyperswitch_connectors/Cargo.toml index 664c78a5f45d..6405ac8ae84f 100644 --- a/crates/hyperswitch_connectors/Cargo.toml +++ b/crates/hyperswitch_connectors/Cargo.toml @@ -16,6 +16,7 @@ actix-web = "4.5.1" async-trait = "0.1.79" base64 = "0.22.0" bytes = "1.6.0" +encoding_rs = "0.8.33" error-stack = "0.4.1" hex = "0.4.3" http = "0.2.12" @@ -31,6 +32,7 @@ ring = "0.17.8" roxmltree = "0.19.0" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" +serde_qs = "0.12.0" serde_urlencoded = "0.7.1" serde_with = "3.7.0" strum = { version = "0.26", features = ["derive"] } diff --git a/crates/hyperswitch_connectors/src/connectors.rs b/crates/hyperswitch_connectors/src/connectors.rs index e7ea31ee0e0b..391d9446cbc6 100644 --- a/crates/hyperswitch_connectors/src/connectors.rs +++ b/crates/hyperswitch_connectors/src/connectors.rs @@ -4,10 +4,12 @@ pub mod bambora; pub mod bamboraapac; pub mod billwerk; pub mod bitpay; +pub mod bluesnap; pub mod boku; pub mod cashtocode; pub mod coinbase; pub mod cryptopay; +pub mod datatrans; pub mod deutschebank; pub mod digitalvirgo; pub mod dlocal; @@ -27,8 +29,10 @@ pub mod nexinets; pub mod nexixpay; pub mod nomupay; pub mod novalnet; +pub mod paybox; pub mod payeezy; pub mod payu; +pub mod placetopay; pub mod powertranz; pub mod prophetpay; pub mod rapyd; @@ -50,12 +54,13 @@ pub mod zsl; pub use self::{ airwallex::Airwallex, amazonpay::Amazonpay, bambora::Bambora, bamboraapac::Bamboraapac, - billwerk::Billwerk, bitpay::Bitpay, boku::Boku, cashtocode::Cashtocode, coinbase::Coinbase, - cryptopay::Cryptopay, 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, payeezy::Payeezy, payu::Payu, + 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, + 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, redsys::Redsys, shift4::Shift4, square::Square, stax::Stax, taxjar::Taxjar, thunes::Thunes, tsys::Tsys, unified_authentication_service::UnifiedAuthenticationService, volt::Volt, diff --git a/crates/router/src/connector/bluesnap.rs b/crates/hyperswitch_connectors/src/connectors/bluesnap.rs similarity index 78% rename from crates/router/src/connector/bluesnap.rs rename to crates/hyperswitch_connectors/src/connectors/bluesnap.rs index dc508a3491d6..3267637b09a7 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/hyperswitch_connectors/src/connectors/bluesnap.rs @@ -1,46 +1,70 @@ pub mod transformers; +use api_models::webhooks::IncomingWebhookEvent; use base64::Engine; +use common_enums::{enums, CallConnectorAction, PaymentAction}; use common_utils::{ + consts::BASE64_ENGINE, crypto, - ext_traits::{StringExt, ValueExt}, - request::RequestContent, + errors::CustomResult, + ext_traits::{BytesExt, StringExt, ValueExt}, + request::{Method, Request, RequestBuilder, RequestContent}, types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, }; -use diesel_models::enums; use error_stack::{report, ResultExt}; -use masking::PeekInterface; -use transformers as bluesnap; - -use super::utils::{ - self as connector_utils, get_error_code_error_message_based_on_priority, ConnectorErrorType, - ConnectorErrorTypeMapping, PaymentsAuthorizeRequestData, RefundsRequestData, RouterData, -}; -use crate::{ - configs::settings, - consts, - core::{ - errors::{self, CustomResult}, - payments, +use hyperswitch_domain_models::{ + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, + CompleteAuthorize, }, - events::connector_api_logs::ConnectorEvent, - headers, logger, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, + router_request_types::{ + AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData, + PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, + PaymentsSyncData, RefundsData, ResponseId, SetupMandateRequestData, }, + router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - transformers::ForeignTryFrom, - ErrorResponse, Response, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsCompleteAuthorizeRouterData, PaymentsSessionRouterData, PaymentsSyncRouterData, + RefundSyncRouterData, RefundsRouterData, + }, +}; +use hyperswitch_interfaces::{ + api::{ + self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse, + ConnectorValidation, + }, + configs::Connectors, + consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE}, + disputes::DisputePayload, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{Mask, PeekInterface}; +use router_env::logger; +use transformers as bluesnap; + +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{ + construct_not_supported_error_report, convert_amount, + get_error_code_error_message_based_on_priority, get_header_key_value, get_http_header, + to_connector_meta_from_secret, to_currency_lower_unit, ConnectorErrorType, + ConnectorErrorTypeMapping, ForeignTryFrom, PaymentsAuthorizeRequestData, + RefundsRequestData, RouterData as _, }, - utils::BytesExt, }; pub const BLUESNAP_TRANSACTION_NOT_FOUND: &str = "is not authorized to view merchant-transaction:"; +pub const REQUEST_TIMEOUT_PAYMENT_NOT_FOUND: &str = "Timed out ,payment not found"; + #[derive(Clone)] pub struct Bluesnap { amount_converter: &'static (dyn AmountConvertor + Sync), @@ -60,9 +84,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut header = self.get_auth_header(&req.connector_auth_type)?; header.push(( headers::CONTENT_TYPE.to_string(), @@ -84,18 +108,18 @@ impl ConnectorCommon for Bluesnap { fn common_get_content_type(&self) -> &'static str { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.bluesnap.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = bluesnap::BluesnapAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; let encoded_api_key = - consts::BASE64_ENGINE.encode(format!("{}:{}", auth.key1.peek(), auth.api_key.peek())); + BASE64_ENGINE.encode(format!("{}:{}", auth.key1.peek(), auth.api_key.peek())); Ok(vec![( headers::AUTHORIZATION.to_string(), format!("Basic {encoded_api_key}").into_masked(), @@ -134,10 +158,10 @@ impl ConnectorCommon for Bluesnap { code: option_error_code_message .clone() .map(|error_code_message| error_code_message.error_code) - .unwrap_or(consts::NO_ERROR_CODE.to_string()), + .unwrap_or(NO_ERROR_CODE.to_string()), message: option_error_code_message .map(|error_code_message| error_code_message.error_message) - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + .unwrap_or(NO_ERROR_MESSAGE.to_string()), reason: Some(reason), attempt_status: None, connector_transaction_id: None, @@ -158,7 +182,7 @@ impl ConnectorCommon for Bluesnap { ( format!( "{} in bluesnap dashboard", - consts::REQUEST_TIMEOUT_PAYMENT_NOT_FOUND + REQUEST_TIMEOUT_PAYMENT_NOT_FOUND ), Some(enums::AttemptStatus::Failure), // when bluesnap throws 403 for payment not found, we update the payment status to failure. ) @@ -167,7 +191,7 @@ impl ConnectorCommon for Bluesnap { }; ErrorResponse { status_code: res.status_code, - code: consts::NO_ERROR_CODE.to_string(), + code: NO_ERROR_CODE.to_string(), message: error_response, reason: Some(error_res), attempt_status, @@ -191,14 +215,14 @@ impl ConnectorValidation for Bluesnap { | enums::CaptureMethod::Manual | enums::CaptureMethod::SequentialAutomatic => Ok(()), enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_supported_error_report(capture_method, self.id()), + construct_not_supported_error_report(capture_method, self.id()), ), } } fn validate_psync_reference_id( &self, - data: &hyperswitch_domain_models::router_request_types::PaymentsSyncData, + data: &PaymentsSyncData, is_three_ds: bool, status: enums::AttemptStatus, connector_meta_data: Option, @@ -222,7 +246,7 @@ impl ConnectorValidation for Bluesnap { } // if merchant_id is present, psync can be made along with attempt_id let meta_data: CustomResult = - connector_utils::to_connector_meta_from_secret(connector_meta_data.clone()); + to_connector_meta_from_secret(connector_meta_data.clone()); meta_data.map(|_| ()) } @@ -232,33 +256,21 @@ impl api::Payment for Bluesnap {} impl api::PaymentToken for Bluesnap {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Bluesnap +impl ConnectorIntegration + for Bluesnap { // Not Implemented (R) } impl api::MandateSetup for Bluesnap {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Bluesnap +impl ConnectorIntegration + for Bluesnap { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Bluesnap".to_string()) .into(), @@ -268,14 +280,12 @@ impl impl api::PaymentVoid for Bluesnap {} -impl ConnectorIntegration - for Bluesnap -{ +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -285,8 +295,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}", @@ -297,8 +307,8 @@ impl ConnectorIntegration CustomResult { let connector_req = bluesnap::BluesnapVoidRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -306,11 +316,11 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Put) + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Put) .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) @@ -323,17 +333,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: bluesnap::BluesnapPaymentsResponse = res .response .parse_struct("BluesnapPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -352,20 +362,15 @@ impl ConnectorIntegration - for Bluesnap -{ -} +impl ConnectorIntegration for Bluesnap {} impl api::PaymentSync for Bluesnap {} -impl ConnectorIntegration - for Bluesnap -{ +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -375,13 +380,13 @@ impl ConnectorIntegration CustomResult { let connector_transaction_id = req.request.connector_transaction_id.clone(); match connector_transaction_id { // if connector_transaction_id is present, we always sync with connector_transaction_id - types::ResponseId::ConnectorTransactionId(trans_id) => { + ResponseId::ConnectorTransactionId(trans_id) => { get_psync_url_with_connector_transaction_id( trans_id, self.base_url(connectors).to_string(), @@ -390,7 +395,7 @@ impl ConnectorIntegration { // if connector_transaction_id is not present, we sync with merchant_transaction_id let meta_data: bluesnap::BluesnapConnectorMetaData = - connector_utils::to_connector_meta_from_secret(req.connector_meta_data.clone()) + to_connector_meta_from_secret(req.connector_meta_data.clone()) .change_context(errors::ConnectorError::ResponseHandlingFailed)?; get_url_with_merchant_transaction_id( self.base_url(connectors).to_string(), @@ -403,12 +408,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) + RequestBuilder::new() + .method(Method::Get) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) @@ -426,17 +431,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: bluesnap::BluesnapPaymentsResponse = res .response .parse_struct("BluesnapPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -446,14 +451,12 @@ impl ConnectorIntegration - for Bluesnap -{ +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -463,8 +466,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}", @@ -475,10 +478,10 @@ impl ConnectorIntegration CustomResult { - let amount_to_capture = connector_utils::convert_amount( + let amount_to_capture = convert_amount( self.amount_converter, req.request.minor_amount_to_capture, req.request.currency, @@ -491,11 +494,11 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Put) + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Put) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -510,17 +513,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: bluesnap::BluesnapPaymentsResponse = res .response .parse_struct("Bluesnap BluesnapPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -540,14 +543,12 @@ impl ConnectorIntegration - for Bluesnap -{ +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::PaymentsSessionRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSessionRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -557,8 +558,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}", @@ -569,8 +570,8 @@ impl ConnectorIntegration CustomResult { let connector_req = bluesnap::BluesnapCreateWalletToken::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -578,12 +579,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSessionRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsSessionType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsSessionType::get_headers( @@ -598,10 +599,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: bluesnap::BluesnapWalletTokenResponse = res .response .parse_struct("BluesnapWalletTokenResponse") @@ -611,11 +612,10 @@ impl ConnectorIntegration - for Bluesnap -{ +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -652,8 +650,8 @@ impl ConnectorIntegration CustomResult { if req.is_three_ds() && req.request.is_card() { Ok(format!( @@ -672,10 +670,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -697,12 +695,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsAuthorizeType::get_url( self, req, connectors, )?) @@ -719,13 +717,13 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { match (data.is_three_ds() && data.request.is_card(), res.headers) { (true, Some(headers)) => { - let location = connector_utils::get_http_header("Location", &headers) + let location = get_http_header("Location", &headers) .change_context(errors::ConnectorError::ResponseHandlingFailed)?; // If location headers are not present connector will return 4XX so this error will never be propagated let payment_fields_token = location .split('/') @@ -739,11 +737,11 @@ impl ConnectorIntegration for Bluesnap +impl ConnectorIntegration + for Bluesnap { fn get_headers( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } fn get_content_type(&self) -> &'static str { @@ -802,8 +796,8 @@ impl } fn get_url( &self, - _req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, + _req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}services/2/transactions", @@ -812,10 +806,10 @@ impl } fn get_request_body( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCompleteAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -827,12 +821,12 @@ impl } fn build_request( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCompleteAuthorizeType::get_url( self, req, connectors, )?) @@ -848,17 +842,17 @@ impl } fn handle_response( &self, - data: &types::PaymentsCompleteAuthorizeRouterData, + data: &PaymentsCompleteAuthorizeRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: bluesnap::BluesnapPaymentsResponse = res .response .parse_struct("BluesnapPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -879,14 +873,12 @@ impl api::Refund for Bluesnap {} impl api::RefundExecute for Bluesnap {} impl api::RefundSync for Bluesnap {} -impl ConnectorIntegration - for Bluesnap -{ +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -896,8 +888,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}{}", @@ -909,10 +901,10 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { - let refund_amount = connector_utils::convert_amount( + let refund_amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -924,11 +916,11 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + 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( @@ -943,17 +935,17 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: bluesnap::RefundResponse = res .response .parse_struct("bluesnap RefundResponse") .change_context(errors::ConnectorError::RequestEncodingFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -970,12 +962,12 @@ impl ConnectorIntegration for Bluesnap { +impl ConnectorIntegration for Bluesnap { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -985,14 +977,14 @@ impl ConnectorIntegration CustomResult { if req.request.payment_amount == req.request.refund_amount { let meta_data: CustomResult< bluesnap::BluesnapConnectorMetaData, errors::ConnectorError, - > = connector_utils::to_connector_meta_from_secret(req.connector_meta_data.clone()); + > = to_connector_meta_from_secret(req.connector_meta_data.clone()); match meta_data { // if merchant_id is present, rsync can be made using merchant_transaction_id @@ -1014,12 +1006,12 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) + RequestBuilder::new() + .method(Method::Get) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundSyncType::get_headers(self, req, connectors)?) @@ -1029,17 +1021,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: bluesnap::BluesnapPaymentsResponse = res .response .parse_struct("bluesnap BluesnapPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -1057,39 +1049,37 @@ impl ConnectorIntegration, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::HmacSha256)) } fn get_webhook_source_verification_signature( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets, ) -> CustomResult, errors::ConnectorError> { - let security_header = - connector_utils::get_header_key_value("bls-signature", request.headers)?; + let security_header = get_header_key_value("bls-signature", request.headers)?; hex::decode(security_header) .change_context(errors::ConnectorError::WebhookSignatureNotFound) } fn get_webhook_source_verification_message( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, _merchant_id: &common_utils::id_type::MerchantId, _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets, ) -> CustomResult, errors::ConnectorError> { - let timestamp = - connector_utils::get_header_key_value("bls-ipn-timestamp", request.headers)?; + let timestamp = get_header_key_value("bls-ipn-timestamp", request.headers)?; Ok(format!("{}{}", timestamp, String::from_utf8_lossy(request.body)).into_bytes()) } fn get_webhook_object_reference_id( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { let webhook_body: bluesnap::BluesnapWebhookBody = serde_urlencoded::from_bytes(request.body) @@ -1131,23 +1121,23 @@ impl api::IncomingWebhook for Bluesnap { fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let details: bluesnap::BluesnapWebhookObjectEventType = serde_urlencoded::from_bytes(request.body) .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; - api::IncomingWebhookEvent::try_from(details) + IncomingWebhookEvent::try_from(details) } fn get_dispute_details( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let dispute_details: bluesnap::BluesnapDisputeWebhookBody = serde_urlencoded::from_bytes(request.body) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; - Ok(api::disputes::DisputePayload { - amount: connector_utils::to_currency_lower_unit( + Ok(DisputePayload { + amount: to_currency_lower_unit( dispute_details.invoice_charge_amount.abs().to_string(), dispute_details.currency, )?, @@ -1165,7 +1155,7 @@ impl api::IncomingWebhook for Bluesnap { fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let resource: bluesnap::BluesnapWebhookObjectResource = serde_urlencoded::from_bytes(request.body) @@ -1175,19 +1165,18 @@ impl api::IncomingWebhook for Bluesnap { } } -impl services::ConnectorRedirectResponse for Bluesnap { +impl ConnectorRedirectResponse for Bluesnap { fn get_flow_type( &self, _query_params: &str, json_payload: Option, - action: services::PaymentAction, - ) -> CustomResult { + action: PaymentAction, + ) -> CustomResult { match action { - services::PaymentAction::PSync - | services::PaymentAction::PaymentAuthenticateCompleteAuthorize => { - Ok(payments::CallConnectorAction::Trigger) + PaymentAction::PSync | PaymentAction::PaymentAuthenticateCompleteAuthorize => { + Ok(CallConnectorAction::Trigger) } - services::PaymentAction::CompleteAuthorize => { + PaymentAction::CompleteAuthorize => { let redirection_response: bluesnap::BluesnapRedirectionResponse = json_payload .ok_or(errors::ConnectorError::MissingConnectorRedirectionPayload { field_name: "json_payload", @@ -1201,8 +1190,8 @@ impl services::ConnectorRedirectResponse for Bluesnap { .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; match redirection_result.status.as_str() { - "Success" => Ok(payments::CallConnectorAction::Trigger), - _ => Ok(payments::CallConnectorAction::StatusUpdate { + "Success" => Ok(CallConnectorAction::Trigger), + _ => Ok(CallConnectorAction::StatusUpdate { status: enums::AttemptStatus::AuthenticationFailed, error_code: redirection_result.code, error_message: redirection_result @@ -1370,7 +1359,7 @@ fn get_psync_url_with_connector_transaction_id( } fn get_rsync_url_with_connector_refund_id( - req: &types::RefundSyncRouterData, + req: &RefundSyncRouterData, base_url: String, ) -> CustomResult { Ok(format!( diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs similarity index 75% rename from crates/router/src/connector/bluesnap/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs index d3fc0779e255..2e4503c34691 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs @@ -1,32 +1,44 @@ use std::collections::HashMap; -use api_models::{enums as api_enums, payments}; +use api_models::{ + payments::{ + AmountInfo, ApplePayPaymentRequest, ApplePaySessionResponse, + ApplepayCombinedSessionTokenData, ApplepaySessionTokenData, ApplepaySessionTokenMetadata, + ApplepaySessionTokenResponse, NextActionCall, NoThirdPartySdkSessionResponse, + SdkNextAction, SessionToken, + }, + webhooks::IncomingWebhookEvent, +}; use base64::Engine; +use common_enums::{enums, CountryAlpha2}; use common_utils::{ + consts::{APPLEPAY_VALIDATION_URL, BASE64_ENGINE}, errors::CustomResult, - ext_traits::{ByteSliceExt, StringExt, ValueExt}, + ext_traits::{ByteSliceExt, Encode, OptionExt, StringExt, ValueExt}, pii::Email, types::StringMajorUnit, }; use error_stack::ResultExt; -use masking::{ExposeInterface, PeekInterface}; +use hyperswitch_domain_models::{ + address::AddressDetails, + payment_method_data::{self, PaymentMethodData, WalletData}, + router_data::{ConnectorAuthType, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::ResponseId, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::errors; +use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::{ - connector::utils::{ - self, AddressDetailsData, ApplePay, CardData, PaymentsAuthorizeRequestData, - PaymentsCompleteAuthorizeRequestData, RouterData, + types::{PaymentsSessionResponseRouterData, RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, AddressDetailsData, ApplePay, CardData as _, ForeignTryFrom, + PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, RouterData as _, }, - consts, - core::errors, - pii::Secret, - types::{ - self, api, domain, - storage::enums, - transformers::{ForeignFrom, ForeignTryFrom}, - }, - utils::{Encode, OptionExt}, }; const DISPLAY_METADATA: &str = "Y"; @@ -150,7 +162,7 @@ pub struct EncodedPaymentToken { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct BillingDetails { - country_code: Option, + country_code: Option, address_lines: Option>>, family_name: Option>, given_name: Option>, @@ -210,28 +222,28 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> item: &BluesnapRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { match item.router_data.request.payment_method_data { - domain::PaymentMethodData::Card(ref ccard) => Ok(Self { + PaymentMethodData::Card(ref ccard) => Ok(Self { cc_number: ccard.card_number.clone(), exp_date: ccard.get_expiry_date_as_mmyyyy("/"), }), - 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::MobilePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::Wallet(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::MobilePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( "Selected payment method via Token flow through bluesnap".to_string(), ) @@ -256,7 +268,7 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues .metadata .as_ref() .map(|metadata| BluesnapMetadata { - meta_data: Vec::::foreign_from(metadata.to_owned()), + meta_data: convert_metadata_to_request_metadata(metadata.to_owned()), }); let (payment_method, card_holder_info) = match item @@ -265,7 +277,7 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues .payment_method_data .clone() { - domain::PaymentMethodData::Card(ref ccard) => Ok(( + PaymentMethodData::Card(ref ccard) => Ok(( PaymentMethodDetails::CreditCard(Card { card_number: ccard.card_number.clone(), expiration_month: ccard.card_exp_month.clone(), @@ -277,8 +289,8 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues item.router_data.request.get_email()?, )?, )), - domain::PaymentMethodData::Wallet(wallet_data) => match wallet_data { - domain::WalletData::GooglePay(payment_method_data) => { + PaymentMethodData::Wallet(wallet_data) => match wallet_data { + WalletData::GooglePay(payment_method_data) => { let gpay_object = BluesnapGooglePayObject { payment_method_data: utils::GooglePayWalletData::from(payment_method_data), } @@ -287,14 +299,12 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues Ok(( PaymentMethodDetails::Wallet(BluesnapWallet { wallet_type: BluesnapWalletTypes::GooglePay, - encoded_payment_token: Secret::new( - consts::BASE64_ENGINE.encode(gpay_object), - ), + encoded_payment_token: Secret::new(BASE64_ENGINE.encode(gpay_object)), }), None, )) } - domain::WalletData::ApplePay(payment_method_data) => { + WalletData::ApplePay(payment_method_data) => { let apple_pay_payment_data = payment_method_data.get_applepay_decoded_payment_data()?; let apple_pay_payment_data: ApplePayEncodedPaymentData = apple_pay_payment_data @@ -346,7 +356,7 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues PaymentMethodDetails::Wallet(BluesnapWallet { wallet_type: BluesnapWalletTypes::ApplePay, encoded_payment_token: Secret::new( - consts::BASE64_ENGINE.encode(apple_pay_object), + BASE64_ENGINE.encode(apple_pay_object), ), }), get_card_holder_info( @@ -355,52 +365,52 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues )?, )) } - domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePayRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect {} - | domain::WalletData::GooglePayRedirect(_) - | domain::WalletData::GooglePayThirdPartySdk(_) - | domain::WalletData::MbWayRedirect(_) - | domain::WalletData::MobilePayRedirect(_) - | domain::WalletData::PaypalRedirect(_) - | domain::WalletData::PaypalSdk(_) - | domain::WalletData::Paze(_) - | domain::WalletData::SamsungPay(_) - | domain::WalletData::TwintRedirect {} - | domain::WalletData::VippsRedirect {} - | domain::WalletData::TouchNGoRedirect(_) - | domain::WalletData::WeChatPayRedirect(_) - | domain::WalletData::CashappQr(_) - | domain::WalletData::SwishQr(_) - | domain::WalletData::WeChatPayQr(_) - | domain::WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( + WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | WalletData::GooglePayRedirect(_) + | WalletData::GooglePayThirdPartySdk(_) + | WalletData::MbWayRedirect(_) + | WalletData::MobilePayRedirect(_) + | WalletData::PaypalRedirect(_) + | WalletData::PaypalSdk(_) + | WalletData::Paze(_) + | WalletData::SamsungPay(_) + | WalletData::TwintRedirect {} + | WalletData::VippsRedirect {} + | WalletData::TouchNGoRedirect(_) + | WalletData::WeChatPayRedirect(_) + | WalletData::CashappQr(_) + | WalletData::SwishQr(_) + | WalletData::WeChatPayQr(_) + | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("bluesnap"), )), }, - 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::MobilePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::MobilePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("bluesnap"), )) @@ -421,8 +431,8 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues } } -impl From for ApplepayPaymentMethod { - fn from(item: domain::ApplepayPaymentMethod) -> Self { +impl From for ApplepayPaymentMethod { + fn from(item: payment_method_data::ApplepayPaymentMethod) -> Self { Self { display_name: item.display_name, network: item.network, @@ -437,27 +447,23 @@ impl TryFrom<&types::PaymentsSessionRouterData> for BluesnapCreateWalletToken { let apple_pay_metadata = item.get_connector_meta()?.expose(); let applepay_metadata = apple_pay_metadata .clone() - .parse_value::( - "ApplepayCombinedSessionTokenData", - ) + .parse_value::("ApplepayCombinedSessionTokenData") .map(|combined_metadata| { - payments::ApplepaySessionTokenMetadata::ApplePayCombined( - combined_metadata.apple_pay_combined, - ) + ApplepaySessionTokenMetadata::ApplePayCombined(combined_metadata.apple_pay_combined) }) .or_else(|_| { apple_pay_metadata - .parse_value::("ApplepaySessionTokenData") + .parse_value::("ApplepaySessionTokenData") .map(|old_metadata| { - payments::ApplepaySessionTokenMetadata::ApplePay(old_metadata.apple_pay) + ApplepaySessionTokenMetadata::ApplePay(old_metadata.apple_pay) }) }) .change_context(errors::ConnectorError::ParsingFailed)?; let session_token_data = match applepay_metadata { - payments::ApplepaySessionTokenMetadata::ApplePay(apple_pay_data) => { + ApplepaySessionTokenMetadata::ApplePay(apple_pay_data) => { Ok(apple_pay_data.session_token_data) } - payments::ApplepaySessionTokenMetadata::ApplePayCombined(_apple_pay_combined_data) => { + ApplepaySessionTokenMetadata::ApplePayCombined(_apple_pay_combined_data) => { Err(errors::ConnectorError::FlowNotSupported { flow: "apple pay combined".to_string(), connector: "bluesnap".to_string(), @@ -472,7 +478,7 @@ impl TryFrom<&types::PaymentsSessionRouterData> for BluesnapCreateWalletToken { Ok(Self { wallet_type: "APPLE_PAY".to_string(), - validation_url: consts::APPLEPAY_VALIDATION_URL.to_string().into(), + validation_url: APPLEPAY_VALIDATION_URL.to_string().into(), domain_name, display_name: Some(session_token_data.display_name), }) @@ -481,92 +487,86 @@ impl TryFrom<&types::PaymentsSessionRouterData> for BluesnapCreateWalletToken { impl ForeignTryFrom<( - types::PaymentsSessionResponseRouterData, + PaymentsSessionResponseRouterData, StringMajorUnit, )> for types::PaymentsSessionRouterData { type Error = error_stack::Report; fn foreign_try_from( (item, apple_pay_amount): ( - types::PaymentsSessionResponseRouterData, + PaymentsSessionResponseRouterData, StringMajorUnit, ), ) -> Result { let response = &item.response; - let wallet_token = consts::BASE64_ENGINE + let wallet_token = BASE64_ENGINE .decode(response.wallet_token.clone().expose()) .change_context(errors::ConnectorError::ResponseHandlingFailed)?; - let session_response: payments::NoThirdPartySdkSessionResponse = wallet_token + let session_response: NoThirdPartySdkSessionResponse = wallet_token .parse_struct("NoThirdPartySdkSessionResponse") .change_context(errors::ConnectorError::ParsingFailed)?; let metadata = item.data.get_connector_meta()?.expose(); let applepay_metadata = metadata .clone() - .parse_value::( - "ApplepayCombinedSessionTokenData", - ) + .parse_value::("ApplepayCombinedSessionTokenData") .map(|combined_metadata| { - payments::ApplepaySessionTokenMetadata::ApplePayCombined( - combined_metadata.apple_pay_combined, - ) + ApplepaySessionTokenMetadata::ApplePayCombined(combined_metadata.apple_pay_combined) }) .or_else(|_| { metadata - .parse_value::("ApplepaySessionTokenData") + .parse_value::("ApplepaySessionTokenData") .map(|old_metadata| { - payments::ApplepaySessionTokenMetadata::ApplePay(old_metadata.apple_pay) + ApplepaySessionTokenMetadata::ApplePay(old_metadata.apple_pay) }) }) .change_context(errors::ConnectorError::ParsingFailed)?; let (payment_request_data, session_token_data) = match applepay_metadata { - payments::ApplepaySessionTokenMetadata::ApplePayCombined(_apple_pay_combined) => { + ApplepaySessionTokenMetadata::ApplePayCombined(_apple_pay_combined) => { Err(errors::ConnectorError::FlowNotSupported { flow: "apple pay combined".to_string(), connector: "bluesnap".to_string(), }) } - payments::ApplepaySessionTokenMetadata::ApplePay(apple_pay) => { + ApplepaySessionTokenMetadata::ApplePay(apple_pay) => { Ok((apple_pay.payment_request_data, apple_pay.session_token_data)) } }?; Ok(Self { - response: Ok(types::PaymentsResponseData::SessionResponse { - session_token: api::SessionToken::ApplePay(Box::new( - payments::ApplepaySessionTokenResponse { - session_token_data: Some( - payments::ApplePaySessionResponse::NoThirdPartySdk(session_response), - ), - payment_request_data: Some(payments::ApplePayPaymentRequest { - country_code: item.data.get_billing_country()?, - currency_code: item.data.request.currency, - total: payments::AmountInfo { - label: payment_request_data.label, - total_type: Some("final".to_string()), - amount: apple_pay_amount, - }, - merchant_capabilities: Some(payment_request_data.merchant_capabilities), - supported_networks: Some(payment_request_data.supported_networks), - merchant_identifier: Some(session_token_data.merchant_identifier), - required_billing_contact_fields: None, - required_shipping_contact_fields: None, - }), - connector: "bluesnap".to_string(), - delayed_session_token: false, - sdk_next_action: { - payments::SdkNextAction { - next_action: payments::NextActionCall::Confirm, - } + response: Ok(PaymentsResponseData::SessionResponse { + session_token: SessionToken::ApplePay(Box::new(ApplepaySessionTokenResponse { + session_token_data: Some(ApplePaySessionResponse::NoThirdPartySdk( + session_response, + )), + payment_request_data: Some(ApplePayPaymentRequest { + country_code: item.data.get_billing_country()?, + currency_code: item.data.request.currency, + total: AmountInfo { + label: payment_request_data.label, + total_type: Some("final".to_string()), + amount: apple_pay_amount, }, - connector_reference_id: None, - connector_sdk_public_key: None, - connector_merchant_id: None, + merchant_capabilities: Some(payment_request_data.merchant_capabilities), + supported_networks: Some(payment_request_data.supported_networks), + merchant_identifier: Some(session_token_data.merchant_identifier), + required_billing_contact_fields: None, + required_shipping_contact_fields: None, + }), + connector: "bluesnap".to_string(), + delayed_session_token: false, + sdk_next_action: { + SdkNextAction { + next_action: NextActionCall::Confirm, + } }, - )), + connector_reference_id: None, + connector_sdk_public_key: None, + connector_merchant_id: None, + })), }), ..item.data }) @@ -612,7 +612,7 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsCompleteAuthorizeRouterData>> .metadata .as_ref() .map(|metadata| BluesnapMetadata { - meta_data: Vec::::foreign_from(metadata.to_owned()), + meta_data: convert_metadata_to_request_metadata(metadata.to_owned()), }); let token = item @@ -745,10 +745,10 @@ pub struct BluesnapAuthType { pub(super) key1: Secret, } -impl TryFrom<&types::ConnectorAuthType> for BluesnapAuthType { +impl TryFrom<&ConnectorAuthType> for BluesnapAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { - if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { + fn try_from(auth_type: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { Ok(Self { api_key: api_key.to_owned(), key1: key1.to_owned(), @@ -855,26 +855,20 @@ pub struct ProcessingInfoResponse { pub network_transaction_id: Option>, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - BluesnapPaymentsResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { Ok(Self { status: enums::AttemptStatus::foreign_try_from(( item.response.card_transaction_type, item.response.processing_info.processing_status, ))?, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( item.response.transaction_id.clone(), ), redirection_data: Box::new(None), @@ -922,15 +916,15 @@ pub struct RefundResponse { refund_status: BluesnapRefundStatus, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_id.clone(), refund_status: enums::RefundStatus::from( item.response.processing_info.processing_status, @@ -941,15 +935,15 @@ impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.refund_transaction_id.to_string(), refund_status: enums::RefundStatus::from(item.response.refund_status), }), @@ -1003,7 +997,7 @@ pub enum BluesnapWebhookEvents { Unknown, } -impl TryFrom for api::IncomingWebhookEvent { +impl TryFrom for IncomingWebhookEvent { type Error = error_stack::Report; fn try_from(details: BluesnapWebhookObjectEventType) -> Result { match details.transaction_type { @@ -1035,7 +1029,7 @@ impl TryFrom for api::IncomingWebhookEvent { #[serde(rename_all = "camelCase")] pub struct BluesnapDisputeWebhookBody { pub invoice_charge_amount: f64, - pub currency: diesel_models::enums::Currency, + pub currency: enums::Currency, pub reversal_reason: Option, pub reversal_ref_num: String, pub cb_status: String, @@ -1125,7 +1119,7 @@ pub enum BluesnapErrors { } fn get_card_holder_info( - address: &hyperswitch_domain_models::address::AddressDetails, + address: &AddressDetails, email: Email, ) -> CustomResult, errors::ConnectorError> { let first_name = address.get_first_name()?; @@ -1145,18 +1139,16 @@ impl From for utils::ErrorCodeAndMessage { } } -impl ForeignFrom for Vec { - fn foreign_from(metadata: Value) -> Self { - let hashmap: HashMap, Option> = - serde_json::from_str(&metadata.to_string()).unwrap_or(HashMap::new()); - let mut vector: Self = Self::new(); - for (key, value) in hashmap { - vector.push(RequestMetadata { - meta_key: key, - meta_value: value.map(|field_value| field_value.to_string()), - is_visible: Some(DISPLAY_METADATA.to_string()), - }); - } - vector +fn convert_metadata_to_request_metadata(metadata: Value) -> Vec { + let hashmap: HashMap, Option> = + serde_json::from_str(&metadata.to_string()).unwrap_or(HashMap::new()); + let mut vector = Vec::::new(); + for (key, value) in hashmap { + vector.push(RequestMetadata { + meta_key: key, + meta_value: value.map(|field_value| field_value.to_string()), + is_visible: Some(DISPLAY_METADATA.to_string()), + }); } + vector } diff --git a/crates/router/src/connector/datatrans.rs b/crates/hyperswitch_connectors/src/connectors/datatrans.rs similarity index 69% rename from crates/router/src/connector/datatrans.rs rename to crates/hyperswitch_connectors/src/connectors/datatrans.rs index 24202b2196fe..081fedc6a36f 100644 --- a/crates/router/src/connector/datatrans.rs +++ b/crates/hyperswitch_connectors/src/connectors/datatrans.rs @@ -1,29 +1,49 @@ pub mod transformers; -use api_models::enums::{CaptureMethod, PaymentMethodType}; + +use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId}; use base64::Engine; -use common_utils::types::{AmountConvertor, MinorUnit, MinorUnitForConnector}; +use common_enums::{CaptureMethod, PaymentMethodType}; +use common_utils::{ + consts::BASE64_ENGINE, + errors::CustomResult, + ext_traits::BytesExt, + request::{Method, Request, RequestBuilder, RequestContent}, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use error_stack::{report, ResultExt}; -use masking::PeekInterface; - -use self::transformers as datatrans; -use super::{utils as connector_utils, utils::RefundsRequestData}; -use crate::{ - configs::settings, - consts, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, +use hyperswitch_domain_models::{ + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, 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}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, RequestContent, Response, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, }, - utils::BytesExt, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{Mask, PeekInterface}; +use transformers as datatrans; + +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{convert_amount, RefundsRequestData}, }; impl api::Payment for Datatrans {} @@ -52,12 +72,8 @@ impl Datatrans { } } -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Datatrans +impl ConnectorIntegration + for Datatrans { // Not Implemented (R) } @@ -68,9 +84,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut header = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -94,18 +110,18 @@ impl ConnectorCommon for Datatrans { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.datatrans.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = datatrans::DatatransAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; let auth_key = format!("{}:{}", auth.merchant_id.peek(), auth.passcode.peek()); - let auth_header = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_key)); + let auth_header = format!("Basic {}", BASE64_ENGINE.encode(auth_key)); Ok(vec![( headers::AUTHORIZATION.to_string(), auth_header.into_masked(), @@ -158,34 +174,23 @@ impl ConnectorValidation for Datatrans { } } -impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { //TODO: implement sessions flow } -impl ConnectorIntegration - for Datatrans -{ -} +impl ConnectorIntegration for Datatrans {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Datatrans +impl ConnectorIntegration + for Datatrans { } -impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -195,8 +200,8 @@ impl ConnectorIntegration CustomResult { let base_url = self.base_url(connectors); Ok(format!("{base_url}v1/transactions/authorize")) @@ -204,10 +209,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -219,12 +224,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsAuthorizeType::get_url( self, req, connectors, )?) @@ -241,17 +246,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: datatrans::DatatransResponse = res .response .parse_struct("Datatrans PaymentsAuthorizeResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -267,14 +272,12 @@ impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -284,8 +287,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req .request @@ -298,12 +301,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) + RequestBuilder::new() + .method(Method::Get) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) @@ -313,17 +316,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: datatrans::DatatransSyncResponse = res .response .parse_struct("datatrans DatatransSyncResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -339,14 +342,12 @@ impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -356,8 +357,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); let base_url = self.base_url(connectors); @@ -368,10 +369,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount_to_capture, req.request.currency, @@ -383,12 +384,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -403,10 +404,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response = if res.response.is_empty() { datatrans::DataTransCaptureResponse::Empty } else { @@ -416,7 +417,7 @@ impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -449,8 +448,8 @@ impl ConnectorIntegration CustomResult { let transaction_id = req.request.connector_transaction_id.clone(); let base_url = self.base_url(connectors); @@ -459,11 +458,11 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) @@ -476,10 +475,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response = if res.response.is_empty() { datatrans::DataTransCancelResponse::Empty } else { @@ -489,7 +488,7 @@ impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -522,8 +519,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { let transaction_id = req.request.connector_transaction_id.clone(); let base_url = self.base_url(connectors); @@ -532,10 +529,10 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -547,11 +544,11 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + 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( @@ -566,10 +563,10 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: datatrans::DatatransRefundsResponse = res .response .parse_struct("datatrans DatatransRefundsResponse") @@ -577,7 +574,7 @@ impl ConnectorIntegration - for Datatrans -{ +impl ConnectorIntegration for Datatrans { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -610,8 +605,8 @@ impl ConnectorIntegration CustomResult { let connector_refund_id = req.request.get_connector_refund_id()?; let base_url = self.base_url(connectors); @@ -620,12 +615,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) + RequestBuilder::new() + .method(Method::Get) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundSyncType::get_headers(self, req, connectors)?) @@ -638,17 +633,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: datatrans::DatatransSyncResponse = res .response .parse_struct("datatrans DatatransSyncResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -665,24 +660,24 @@ impl ConnectorIntegration, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } diff --git a/crates/router/src/connector/datatrans/transformers.rs b/crates/hyperswitch_connectors/src/connectors/datatrans/transformers.rs similarity index 75% rename from crates/router/src/connector/datatrans/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/datatrans/transformers.rs index 7d52e64b4b7c..2ec76cb2937e 100644 --- a/crates/router/src/connector/datatrans/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/datatrans/transformers.rs @@ -1,20 +1,24 @@ -use std::fmt::Debug; - +use common_enums::enums; use common_utils::types::MinorUnit; +use hyperswitch_domain_models::{ + payment_method_data::PaymentMethodData, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::{PaymentsAuthorizeData, ResponseId}, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::errors; use masking::Secret; use serde::{Deserialize, Serialize}; use crate::{ - connector::{ - utils as connector_utils, - utils::{CardData, PaymentsAuthorizeRequestData}, - }, - core::errors, types::{ - self, - api::{self, enums}, - domain, - transformers::ForeignFrom, + PaymentsCancelResponseRouterData, PaymentsCaptureResponseRouterData, + PaymentsSyncResponseRouterData, RefundsResponseRouterData, ResponseRouterData, + }, + utils::{ + get_unimplemented_payment_method_error_message, CardData as _, PaymentsAuthorizeRequestData, }, }; @@ -159,7 +163,7 @@ impl TryFrom<&DatatransRouterData<&types::PaymentsAuthorizeRouterData>> item: &DatatransRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { match item.router_data.request.payment_method_data.clone() { - domain::PaymentMethodData::Card(req_card) => Ok(Self { + PaymentMethodData::Card(req_card) => Ok(Self { amount: item.amount, currency: item.router_data.request.currency, card: PlainCardDetails { @@ -174,36 +178,36 @@ impl TryFrom<&DatatransRouterData<&types::PaymentsAuthorizeRouterData>> Some(enums::CaptureMethod::Automatic) ), }), - 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::MobilePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::Wallet(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::MobilePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( - connector_utils::get_unimplemented_payment_method_error_message("Datatrans"), + get_unimplemented_payment_method_error_message("Datatrans"), ))? } } } } -impl TryFrom<&types::ConnectorAuthType> for DatatransAuthType { +impl TryFrom<&ConnectorAuthType> for DatatransAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { + ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { merchant_id: key1.clone(), passcode: api_key.clone(), }), @@ -212,20 +216,19 @@ impl TryFrom<&types::ConnectorAuthType> for DatatransAuthType { } } -impl ForeignFrom<(&DatatransResponse, bool)> for enums::AttemptStatus { - fn foreign_from((item, is_auto_capture): (&DatatransResponse, bool)) -> Self { - match item { - DatatransResponse::ErrorResponse(_) => Self::Failure, - DatatransResponse::TransactionResponse(_) => { - if is_auto_capture { - Self::Charged - } else { - Self::Authorized - } +fn get_status(item: &DatatransResponse, is_auto_capture: bool) -> enums::AttemptStatus { + match item { + DatatransResponse::ErrorResponse(_) => enums::AttemptStatus::Failure, + DatatransResponse::TransactionResponse(_) => { + if is_auto_capture { + enums::AttemptStatus::Charged + } else { + enums::AttemptStatus::Authorized } } } } + impl From for enums::AttemptStatus { fn from(item: SyncResponse) -> Self { match item.res_type { @@ -258,30 +261,16 @@ impl From for enums::RefundStatus { } impl - TryFrom< - types::ResponseRouterData< - F, - DatatransResponse, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, - > for types::RouterData + TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - DatatransResponse, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { - let status = enums::AttemptStatus::foreign_from(( - &item.response, - item.data.request.is_auto_capture()?, - )); + let status = get_status(&item.response, item.data.request.is_auto_capture()?); let response = match &item.response { - DatatransResponse::ErrorResponse(error) => Err(types::ErrorResponse { + DatatransResponse::ErrorResponse(error) => Err(ErrorResponse { code: error.code.clone(), message: error.message.clone(), reason: Some(error.message.clone()), @@ -290,8 +279,8 @@ impl status_code: item.http_code, }), DatatransResponse::TransactionResponse(response) => { - Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( response.transaction_id.clone(), ), redirection_data: Box::new(None), @@ -325,16 +314,16 @@ impl TryFrom<&DatatransRouterData<&types::RefundsRouterData>> for Datatran } } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { match item.response { DatatransRefundsResponse::Error(error) => Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: error.code.clone(), message: error.message.clone(), reason: Some(error.message), @@ -345,7 +334,7 @@ impl TryFrom Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: response.transaction_id, refund_status: enums::RefundStatus::Success, }), @@ -355,15 +344,15 @@ impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let response = match item.response { - DatatransSyncResponse::Error(error) => Err(types::ErrorResponse { + DatatransSyncResponse::Error(error) => Err(ErrorResponse { code: error.code.clone(), message: error.message.clone(), reason: Some(error.message), @@ -371,7 +360,7 @@ impl TryFrom connector_transaction_id: None, status_code: item.http_code, }), - DatatransSyncResponse::Response(response) => Ok(types::RefundsResponseData { + DatatransSyncResponse::Response(response) => Ok(RefundsResponseData { connector_refund_id: response.transaction_id.to_string(), refund_status: enums::RefundStatus::from(response), }), @@ -383,16 +372,16 @@ impl TryFrom } } -impl TryFrom> +impl TryFrom> for types::PaymentsSyncRouterData { type Error = error_stack::Report; fn try_from( - item: types::PaymentsSyncResponseRouterData, + item: PaymentsSyncResponseRouterData, ) -> Result { match item.response { DatatransSyncResponse::Error(error) => { - let response = Err(types::ErrorResponse { + let response = Err(ErrorResponse { code: error.code.clone(), message: error.message.clone(), reason: Some(error.message), @@ -407,10 +396,10 @@ impl TryFrom> } DatatransSyncResponse::Response(response) => { let resource_id = - types::ResponseId::ConnectorTransactionId(response.transaction_id.to_string()); + ResponseId::ConnectorTransactionId(response.transaction_id.to_string()); Ok(Self { status: enums::AttemptStatus::from(response), - response: Ok(types::PaymentsResponseData::TransactionResponse { + response: Ok(PaymentsResponseData::TransactionResponse { resource_id, redirection_data: Box::new(None), mandate_reference: Box::new(None), @@ -442,13 +431,13 @@ impl TryFrom<&DatatransRouterData<&types::PaymentsCaptureRouterData>> } } -impl TryFrom> +impl TryFrom> for types::PaymentsCaptureRouterData { type Error = error_stack::Report; fn try_from( - item: types::PaymentsCaptureResponseRouterData, + item: PaymentsCaptureResponseRouterData, ) -> Result { let status = match item.response { DataTransCaptureResponse::Error(error) => { @@ -475,13 +464,13 @@ impl TryFrom> } } -impl TryFrom> +impl TryFrom> for types::PaymentsCancelRouterData { type Error = error_stack::Report; fn try_from( - item: types::PaymentsCancelResponseRouterData, + item: PaymentsCancelResponseRouterData, ) -> Result { let status = match item.response { // Datatrans http code 204 implies Successful Cancellation diff --git a/crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs b/crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs index 25327358e7fe..d64c2ed8efde 100644 --- a/crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs @@ -1,10 +1,10 @@ -use api_models::enums::{CountryAlpha2, UsStatesAbbreviation}; -use common_enums::{AttemptStatus, Currency, RefundStatus}; +use common_enums::{enums, CountryAlpha2, UsStatesAbbreviation}; use common_utils::{ id_type, pii::{self, IpAddress}, }; use hyperswitch_domain_models::{ + address::AddressDetails, payment_method_data::{BankDebitData, PaymentMethodData}, router_data::{ConnectorAuthType, PaymentMethodToken, RouterData}, router_flow_types::refunds::Execute, @@ -32,10 +32,10 @@ pub struct GocardlessRouterData { pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, Currency, i64, T)> for GocardlessRouterData { +impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for GocardlessRouterData { type Error = error_stack::Report; fn try_from( - (_currency_unit, _currency, amount, item): (&api::CurrencyUnit, Currency, i64, T), + (_currency_unit, _currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), ) -> Result { Ok(Self { amount, @@ -111,7 +111,7 @@ impl TryFrom<&types::ConnectorCustomerRouterData> for GocardlessCustomerRequest } fn get_region( - address_details: &hyperswitch_domain_models::address::AddressDetails, + address_details: &AddressDetails, ) -> Result>, error_stack::Report> { match address_details.country { Some(CountryAlpha2::US) => { @@ -532,7 +532,7 @@ impl network_txn_id: None, charge_id: None, }), - status: AttemptStatus::Charged, + status: enums::AttemptStatus::Charged, ..item.data }) } @@ -546,7 +546,7 @@ pub struct GocardlessPaymentsRequest { #[derive(Debug, Serialize)] pub struct GocardlessPayment { amount: i64, - currency: Currency, + currency: enums::Currency, description: Option, metadata: PaymentMetaData, links: PaymentLink, @@ -625,7 +625,7 @@ pub enum GocardlessPaymentStatus { Failed, } -impl From for AttemptStatus { +impl From for enums::AttemptStatus { fn from(item: GocardlessPaymentStatus) -> Self { match item { GocardlessPaymentStatus::PendingCustomerApproval @@ -676,7 +676,7 @@ impl connector_mandate_request_reference_id: None, }; Ok(Self { - status: AttemptStatus::from(item.response.payments.status), + status: enums::AttemptStatus::from(item.response.payments.status), response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.payments.id), redirection_data: Box::new(None), @@ -707,7 +707,7 @@ impl >, ) -> Result { Ok(Self { - status: AttemptStatus::from(item.response.payments.status), + status: enums::AttemptStatus::from(item.response.payments.status), response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId(item.response.payments.id), redirection_data: Box::new(None), @@ -780,7 +780,7 @@ impl TryFrom> Ok(Self { response: Ok(RefundsResponseData { connector_refund_id: item.response.id.to_string(), - refund_status: RefundStatus::Pending, + refund_status: enums::RefundStatus::Pending, }), ..item.data }) diff --git a/crates/router/src/connector/paybox.rs b/crates/hyperswitch_connectors/src/connectors/paybox.rs similarity index 65% rename from crates/router/src/connector/paybox.rs rename to crates/hyperswitch_connectors/src/connectors/paybox.rs index 99959ca87e58..4f85f31c698e 100644 --- a/crates/router/src/connector/paybox.rs +++ b/crates/hyperswitch_connectors/src/connectors/paybox.rs @@ -1,34 +1,53 @@ pub mod transformers; -use common_enums::enums; -use common_utils::types::{AmountConvertor, MinorUnit, MinorUnitForConnector}; -use error_stack::{report, ResultExt}; -use masking::ExposeInterface; -use transformers as paybox; - -use super::utils::{ - RouterData, {self as connector_utils}, +use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId}; +use common_enums::{enums, CallConnectorAction, PaymentAction}; +use common_utils::{ + errors::CustomResult, + ext_traits::BytesExt, + request::{Method, Request, RequestBuilder, RequestContent}, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, }; -use crate::{ - configs::settings, - connector::{utils, utils::PaymentMethodDataType}, - core::{ - errors::{self, CustomResult}, - payments, +use error_stack::{report, ResultExt}; +use hyperswitch_domain_models::{ + payment_method_data::PaymentMethodData, + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, + CompleteAuthorize, }, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, + router_request_types::{ + AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData, + PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, + PaymentsSyncData, RefundsData, SetupMandateRequestData, }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, RequestContent, Response, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsCompleteAuthorizeRouterData, PaymentsSyncRouterData, RefundSyncRouterData, + RefundsRouterData, + }, +}; +use hyperswitch_interfaces::{ + api::{ + self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse, + ConnectorValidation, }, - utils::BytesExt, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{ExposeInterface, Mask}; +use transformers as paybox; + +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{self, convert_amount, is_mandate_supported, PaymentMethodDataType, RouterData as _}, }; #[derive(Clone)] @@ -57,24 +76,18 @@ impl api::RefundExecute for Paybox {} impl api::RefundSync for Paybox {} impl api::PaymentToken for Paybox {} impl api::PaymentsCompleteAuthorize for Paybox {} -impl ConnectorIntegration - for Paybox -{ +impl ConnectorIntegration for Paybox { fn build_request( &self, - _req: &types::PaymentsCancelRouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &PaymentsCancelRouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotImplemented("Cancel/Void flow".to_string()).into()) } } -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Paybox +impl ConnectorIntegration + for Paybox { } @@ -84,9 +97,9 @@ where { fn build_headers( &self, - _req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let header = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -104,14 +117,14 @@ impl ConnectorCommon for Paybox { "application/x-www-form-urlencoded" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.paybox.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = paybox::PayboxAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( @@ -163,39 +176,24 @@ impl ConnectorValidation for Paybox { fn validate_mandate_payment( &self, pm_type: Option, - pm_data: types::domain::payments::PaymentMethodData, + pm_data: PaymentMethodData, ) -> CustomResult<(), errors::ConnectorError> { let mandate_supported_pmd = std::collections::HashSet::from([PaymentMethodDataType::Card]); - connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) + is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) } } -impl ConnectorIntegration - for Paybox -{ -} +impl ConnectorIntegration for Paybox {} -impl ConnectorIntegration - for Paybox -{ -} +impl ConnectorIntegration for Paybox {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Paybox -{ -} -impl ConnectorIntegration - for Paybox -{ +impl ConnectorIntegration for Paybox {} +impl ConnectorIntegration for Paybox { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -205,8 +203,8 @@ impl ConnectorIntegration CustomResult { if req.is_three_ds() { Ok(format!( @@ -220,10 +218,10 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -236,12 +234,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsAuthorizeType::get_url( self, req, connectors, )?) @@ -255,15 +253,15 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: paybox::PayboxResponse = paybox::parse_paybox_response(res.response, data.is_three_ds())?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -279,14 +277,12 @@ impl ConnectorIntegration - for Paybox -{ +impl ConnectorIntegration for Paybox { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -295,28 +291,28 @@ impl ConnectorIntegration CustomResult { let connector_req = paybox::PayboxPSyncRequest::try_from(req)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } fn get_url( &self, - _req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, + _req: &PaymentsSyncRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn build_request( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() .set_body(types::PaymentsSyncType::get_request_body( @@ -328,15 +324,15 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: paybox::PayboxSyncResponse = paybox::parse_url_encoded_to_struct(res.response)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -352,14 +348,12 @@ impl ConnectorIntegration - for Paybox -{ +impl ConnectorIntegration for Paybox { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -369,18 +363,18 @@ impl ConnectorIntegration CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, - req: &types::PaymentsCaptureRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCaptureRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount_to_capture, req.request.currency, @@ -393,12 +387,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .set_body(types::PaymentsCaptureType::get_request_body( @@ -410,16 +404,16 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: paybox::PayboxCaptureResponse = paybox::parse_url_encoded_to_struct(res.response)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -435,12 +429,12 @@ impl ConnectorIntegration for Paybox { +impl ConnectorIntegration for Paybox { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -450,18 +444,18 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + _req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, - req: &types::RefundsRouterData, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { - let refund_amount = connector_utils::convert_amount( + let refund_amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -474,11 +468,11 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + 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() .set_body(types::RefundExecuteType::get_request_body( @@ -490,15 +484,15 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: paybox::TransactionResponse = paybox::parse_url_encoded_to_struct(res.response)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -514,12 +508,12 @@ impl ConnectorIntegration for Paybox { +impl ConnectorIntegration for Paybox { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -529,16 +523,16 @@ impl ConnectorIntegration CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, - req: &types::RefundSyncRouterData, - _connectors: &settings::Connectors, + req: &RefundSyncRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_req = paybox::PayboxRsyncRequest::try_from(req)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) @@ -546,12 +540,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .set_body(types::RefundSyncType::get_request_body( @@ -563,15 +557,15 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: paybox::PayboxSyncResponse = paybox::parse_url_encoded_to_struct(res.response)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -588,41 +582,37 @@ impl ConnectorIntegration, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } } -impl - ConnectorIntegration< - api::CompleteAuthorize, - types::CompleteAuthorizeData, - types::PaymentsResponseData, - > for Paybox +impl ConnectorIntegration + for Paybox { fn get_headers( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } fn get_content_type(&self) -> &'static str { @@ -630,17 +620,17 @@ impl } fn get_url( &self, - _req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, + _req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCompleteAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount = utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -652,12 +642,12 @@ impl } fn build_request( &self, - req: &types::PaymentsCompleteAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &PaymentsCompleteAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCompleteAuthorizeType::get_url( self, req, connectors, )?) @@ -672,15 +662,15 @@ impl } fn handle_response( &self, - data: &types::PaymentsCompleteAuthorizeRouterData, + data: &PaymentsCompleteAuthorizeRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: paybox::TransactionResponse = paybox::parse_url_encoded_to_struct(res.response)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -695,18 +685,18 @@ impl self.build_error_response(res, event_builder) } } -impl services::ConnectorRedirectResponse for Paybox { +impl ConnectorRedirectResponse for Paybox { fn get_flow_type( &self, _query_params: &str, _json_payload: Option, - action: services::PaymentAction, - ) -> CustomResult { + action: PaymentAction, + ) -> CustomResult { match action { - services::PaymentAction::PSync - | services::PaymentAction::CompleteAuthorize - | services::PaymentAction::PaymentAuthenticateCompleteAuthorize => { - Ok(payments::CallConnectorAction::Trigger) + PaymentAction::PSync + | PaymentAction::CompleteAuthorize + | PaymentAction::PaymentAuthenticateCompleteAuthorize => { + Ok(CallConnectorAction::Trigger) } } } diff --git a/crates/router/src/connector/paybox/transformers.rs b/crates/hyperswitch_connectors/src/connectors/paybox/transformers.rs similarity index 90% rename from crates/router/src/connector/paybox/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/paybox/transformers.rs index 80e3e0ef0752..effe6df28db2 100644 --- a/crates/router/src/connector/paybox/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/paybox/transformers.rs @@ -1,25 +1,34 @@ use api_models::payments::AdditionalPaymentData; use bytes::Bytes; +use common_enums::enums; use common_utils::{ date_time::DateFormat, errors::CustomResult, ext_traits::ValueExt, types::MinorUnit, }; use error_stack::ResultExt; -use hyperswitch_connectors::utils::{AddressDetailsData, CardData}; use hyperswitch_domain_models::{ - router_data::ConnectorAuthType, router_response_types::RedirectForm, + payment_method_data::PaymentMethodData, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::{CompleteAuthorizeData, PaymentsAuthorizeData, ResponseId}, + router_response_types::{ + MandateReference, PaymentsResponseData, RedirectForm, RefundsResponseData, + }, + types, +}; +use hyperswitch_interfaces::{ + consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE}, + errors, }; -use hyperswitch_interfaces::consts; use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - connector::utils::{ - self, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, RouterData, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, AddressDetailsData, CardData as _, PaymentsAuthorizeRequestData, + PaymentsCompleteAuthorizeRequestData, RouterData as _, }, - core::errors, - types::{self, api, domain, storage::enums, MandateReference}, }; - pub struct PayboxRouterData { pub amount: MinorUnit, pub router_data: T, @@ -189,7 +198,7 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsCaptureRouterData>> for PayboxCap let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.router_data.connector_auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - let currency = item.router_data.request.currency.iso_4217().to_string(); + let currency = enums::Currency::iso_4217(item.router_data.request.currency).to_string(); let paybox_meta_data: PayboxMeta = utils::to_connector_meta(item.router_data.request.connector_meta.clone())?; let format_time = common_utils::date_time::format_date( @@ -378,7 +387,7 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP item: &PayboxRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { match item.router_data.request.payment_method_data.clone() { - domain::PaymentMethodData::Card(req_card) => { + PaymentMethodData::Card(req_card) => { let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.router_data.connector_auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; @@ -386,7 +395,8 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP item.router_data.request.capture_method, item.router_data.request.is_mandate_payment(), )?; - let currency = item.router_data.request.currency.iso_4217().to_string(); + let currency = + enums::Currency::iso_4217(item.router_data.request.currency).to_string(); let expiration_date = req_card.get_card_expiry_month_year_2_digit_with_delimiter("".to_owned())?; let format_time = common_utils::date_time::format_date( @@ -453,7 +463,7 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP })) } } - domain::PaymentMethodData::MandatePayment => { + PaymentMethodData::MandatePayment => { let mandate_data = extract_card_mandate_info( item.router_data .request @@ -667,23 +677,20 @@ pub struct PayboxCaptureResponse { pub response_message: String, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let response = item.response.clone(); let status = get_status_of_request(response.response_code.clone()); match status { true => Ok(Self { status: enums::AttemptStatus::Charged, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - response.paybox_order_id, - ), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(response.paybox_order_id), redirection_data: Box::new(None), mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(PayboxMeta { @@ -698,7 +705,7 @@ impl ..item.data }), false => Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: response.response_code.clone(), message: response.response_message.clone(), reason: Some(response.response_message), @@ -712,24 +719,12 @@ impl } } -impl - TryFrom< - types::ResponseRouterData< - F, - PayboxResponse, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, - > for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - PayboxResponse, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { match item.response.clone() { PayboxResponse::NonThreeDs(response) => { @@ -743,8 +738,8 @@ impl (_, true) | (false, false) => enums::AttemptStatus::Authorized, (true, false) => enums::AttemptStatus::Charged, }, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( response.paybox_order_id, ), redirection_data: Box::new(None), @@ -768,7 +763,7 @@ impl ..item.data }), false => Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: response.response_code.clone(), message: response.response_message.clone(), reason: Some(response.response_message), @@ -782,8 +777,8 @@ impl } PayboxResponse::ThreeDs(data) => Ok(Self { status: enums::AttemptStatus::AuthenticationPending, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::NoResponseId, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, redirection_data: Box::new(Some(RedirectForm::Html { html_data: data.peek().to_string(), })), @@ -797,10 +792,10 @@ impl ..item.data }), PayboxResponse::Error(_) => Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: consts::NO_ERROR_MESSAGE.to_string(), - reason: Some(consts::NO_ERROR_MESSAGE.to_string()), + response: Err(ErrorResponse { + code: NO_ERROR_CODE.to_string(), + message: NO_ERROR_MESSAGE.to_string(), + reason: Some(NO_ERROR_MESSAGE.to_string()), status_code: item.http_code, attempt_status: None, connector_transaction_id: None, @@ -811,12 +806,12 @@ impl } } -impl TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let response = item.response.clone(); let status = get_status_of_request(response.response_code.clone()); @@ -825,10 +820,8 @@ impl TryFrom Ok(Self { status: enums::AttemptStatus::from(connector_payment_status), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - response.paybox_order_id, - ), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(response.paybox_order_id), redirection_data: Box::new(None), mandate_reference: Box::new(None), connector_metadata: Some(serde_json::json!(PayboxMeta { @@ -842,7 +835,7 @@ impl TryFrom Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: response.response_code.clone(), message: response.response_message.clone(), reason: Some(response.response_message), @@ -889,7 +882,7 @@ impl TryFrom<&PayboxRouterData<&types::RefundsRouterData>> for PayboxRefun let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.router_data.connector_auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - let currency = item.router_data.request.currency.iso_4217().to_string(); + let currency = enums::Currency::iso_4217(item.router_data.request.currency).to_string(); let format_time = common_utils::date_time::format_date( common_utils::date_time::now(), DateFormat::DDMMYYYYHHmmss, @@ -913,24 +906,24 @@ impl TryFrom<&PayboxRouterData<&types::RefundsRouterData>> for PayboxRefun } } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let status = get_status_of_request(item.response.response_code.clone()); match status { true => Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_number, refund_status: enums::RefundStatus::from(item.response.status), }), ..item.data }), false => Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: item.response.response_code.clone(), message: item.response.response_message.clone(), reason: Some(item.response.response_message), @@ -944,24 +937,24 @@ impl TryFrom> } } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let status = get_status_of_request(item.response.response_code.clone()); match status { true => Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_number, refund_status: common_enums::RefundStatus::Pending, }), ..item.data }), false => Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: item.response.response_code.clone(), message: item.response.response_message.clone(), reason: Some(item.response.response_message), @@ -983,22 +976,16 @@ pub struct PayboxErrorResponse { } impl - TryFrom< - types::ResponseRouterData< - F, - TransactionResponse, - types::CompleteAuthorizeData, - types::PaymentsResponseData, - >, - > for types::RouterData + TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< + item: ResponseRouterData< F, TransactionResponse, - types::CompleteAuthorizeData, - types::PaymentsResponseData, + CompleteAuthorizeData, + PaymentsResponseData, >, ) -> Result { let response = item.response.clone(); @@ -1012,10 +999,8 @@ impl (_, true) | (false, false) => enums::AttemptStatus::Authorized, (true, false) => enums::AttemptStatus::Charged, }, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - response.paybox_order_id, - ), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(response.paybox_order_id), redirection_data: Box::new(None), mandate_reference: Box::new(response.carrier_id.as_ref().map(|pm| { MandateReference { @@ -1038,7 +1023,7 @@ impl ..item.data }), false => Ok(Self { - response: Err(types::ErrorResponse { + response: Err(ErrorResponse { code: response.response_code.clone(), message: response.response_message.clone(), reason: Some(response.response_message), @@ -1078,7 +1063,7 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for .parse_value("RedirectionAuthResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; match item.router_data.request.payment_method_data.clone() { - Some(domain::PaymentMethodData::Card(req_card)) => { + Some(PaymentMethodData::Card(req_card)) => { let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.router_data.connector_auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; @@ -1086,7 +1071,8 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for item.router_data.request.capture_method, item.router_data.request.is_mandate_payment(), )?; - let currency = item.router_data.request.currency.iso_4217().to_string(); + let currency = + enums::Currency::iso_4217(item.router_data.request.currency).to_string(); let expiration_date = req_card.get_card_expiry_month_year_2_digit_with_delimiter("".to_owned())?; let format_time = common_utils::date_time::format_date( @@ -1201,7 +1187,7 @@ impl Some(enums::CaptureMethod::Manual) => Ok(MANDATE_AUTH_ONLY.to_string()), _ => Err(errors::ConnectorError::CaptureMethodNotSupported), }?; - let currency = item.router_data.request.currency.iso_4217().to_string(); + let currency = enums::Currency::iso_4217(item.router_data.request.currency).to_string(); let format_time = common_utils::date_time::format_date( common_utils::date_time::now(), DateFormat::DDMMYYYYHHmmss, diff --git a/crates/router/src/connector/placetopay.rs b/crates/hyperswitch_connectors/src/connectors/placetopay.rs similarity index 67% rename from crates/router/src/connector/placetopay.rs rename to crates/hyperswitch_connectors/src/connectors/placetopay.rs index c6cc244024dd..5f8426e75bad 100644 --- a/crates/router/src/connector/placetopay.rs +++ b/crates/hyperswitch_connectors/src/connectors/placetopay.rs @@ -1,29 +1,46 @@ pub mod transformers; +use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId}; +use common_enums::enums; use common_utils::{ - request::RequestContent, + errors::CustomResult, + ext_traits::BytesExt, + request::{Method, Request, RequestBuilder, RequestContent}, types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, }; use error_stack::{report, ResultExt}; -use transformers as placetopay; - -use crate::{ - configs::settings, - connector::utils as connector_utils, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self}, - ConnectorIntegration, ConnectorValidation, +use hyperswitch_domain_models::{ + router_data::{AccessToken, ErrorResponse, 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}, types::{ - self, - api::{self, enums, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, Response, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, }, - utils::BytesExt, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use transformers as placetopay; + +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{construct_not_supported_error_report, convert_amount}, }; #[derive(Clone)] @@ -52,12 +69,8 @@ impl api::RefundExecute for Placetopay {} impl api::RefundSync for Placetopay {} impl api::PaymentToken for Placetopay {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Placetopay +impl ConnectorIntegration + for Placetopay { // Not Implemented (R) } @@ -68,9 +81,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut header = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -94,7 +107,7 @@ impl ConnectorCommon for Placetopay { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.placetopay.base_url.as_ref() } @@ -133,39 +146,26 @@ impl ConnectorValidation for Placetopay { enums::CaptureMethod::Automatic | enums::CaptureMethod::SequentialAutomatic => Ok(()), enums::CaptureMethod::Manual | enums::CaptureMethod::ManualMultiple - | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_supported_error_report(capture_method, self.id()), - ), + | enums::CaptureMethod::Scheduled => Err(construct_not_supported_error_report( + capture_method, + self.id(), + )), } } } -impl ConnectorIntegration - for Placetopay -{ -} +impl ConnectorIntegration for Placetopay {} -impl ConnectorIntegration - for Placetopay -{ -} +impl ConnectorIntegration for Placetopay {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Placetopay +impl ConnectorIntegration + for Placetopay { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Placetopay".to_string()) .into(), @@ -173,14 +173,12 @@ impl } } -impl ConnectorIntegration - for Placetopay -{ +impl ConnectorIntegration for Placetopay { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -190,18 +188,18 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}/process", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -213,12 +211,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsAuthorizeType::get_url( self, req, connectors, )?) @@ -235,10 +233,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: placetopay::PlacetopayPaymentsResponse = res .response .parse_struct("Placetopay PlacetopayPaymentsResponse") @@ -247,7 +245,7 @@ impl ConnectorIntegration - for Placetopay -{ +impl ConnectorIntegration for Placetopay { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -280,16 +276,16 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}/query", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsSyncRouterData, - _connectors: &settings::Connectors, + req: &PaymentsSyncRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = placetopay::PlacetopayPsyncRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(req_obj))) @@ -297,12 +293,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) @@ -315,10 +311,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: placetopay::PlacetopayPaymentsResponse = res .response .parse_struct("placetopay PaymentsSyncResponse") @@ -327,7 +323,7 @@ impl ConnectorIntegration - for Placetopay -{ +impl ConnectorIntegration for Placetopay { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -360,16 +354,16 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}/transaction", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsCaptureRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCaptureRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = placetopay::PlacetopayNextActionRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(req_obj))) @@ -377,12 +371,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -397,10 +391,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: placetopay::PlacetopayPaymentsResponse = res .response .parse_struct("Placetopay PaymentsCaptureResponse") @@ -409,7 +403,7 @@ impl ConnectorIntegration - for Placetopay -{ +impl ConnectorIntegration for Placetopay { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -442,16 +434,16 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}/transaction", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsCancelRouterData, - _connectors: &settings::Connectors, + req: &PaymentsCancelRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = placetopay::PlacetopayNextActionRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(req_obj))) @@ -459,12 +451,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) @@ -477,10 +469,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: placetopay::PlacetopayPaymentsResponse = res .response .parse_struct("Placetopay PaymentCancelResponse") @@ -489,7 +481,7 @@ impl ConnectorIntegration - for Placetopay -{ +impl ConnectorIntegration for Placetopay { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -522,16 +512,16 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + _req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!("{}/transaction", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::RefundsRouterData, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = placetopay::PlacetopayRefundRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(req_obj))) @@ -539,11 +529,11 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + 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( @@ -558,10 +548,10 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: placetopay::PlacetopayRefundResponse = res .response .parse_struct("placetopay PlacetopayRefundResponse") @@ -570,7 +560,7 @@ impl ConnectorIntegration - for Placetopay -{ +impl ConnectorIntegration for Placetopay { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -603,16 +591,16 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}/query", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::RefundsRouterData, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let req_obj = placetopay::PlacetopayRsyncRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(req_obj))) @@ -620,12 +608,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundSyncType::get_headers(self, req, connectors)?) @@ -638,10 +626,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: placetopay::PlacetopayRefundResponse = res .response .parse_struct("placetopay PlacetopayRefundResponse") @@ -650,7 +638,7 @@ impl ConnectorIntegration, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } diff --git a/crates/router/src/connector/placetopay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/placetopay/transformers.rs similarity index 81% rename from crates/router/src/connector/placetopay/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/placetopay/transformers.rs index d809b9e770d8..e51093c28d89 100644 --- a/crates/router/src/connector/placetopay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/placetopay/transformers.rs @@ -1,18 +1,25 @@ -use common_utils::{date_time, types::MinorUnit}; -use diesel_models::enums; +use common_enums::{enums, Currency}; +use common_utils::{consts::BASE64_ENGINE, date_time, types::MinorUnit}; use error_stack::ResultExt; +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, +}; +use hyperswitch_interfaces::errors; use masking::{PeekInterface, Secret}; use ring::digest; use serde::{Deserialize, Serialize}; use crate::{ - connector::utils::{ - self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, - PaymentsSyncRequestData, RouterData, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, generate_random_bytes, BrowserInformationData, CardData as _, + PaymentsAuthorizeRequestData, PaymentsSyncRequestData, RouterData as _, }, - consts, - core::errors, - types::{self, api, domain, storage::enums as storage_enums}, }; pub struct PlacetopayRouterData { @@ -72,7 +79,7 @@ pub struct PlacetopayPayment { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct PlacetopayAmount { - currency: storage_enums::Currency, + currency: Currency, total: MinorUnit, } @@ -110,7 +117,7 @@ impl TryFrom<&PlacetopayRouterData<&types::PaymentsAuthorizeRouterData>> }, }; match item.router_data.request.payment_method_data.clone() { - domain::PaymentMethodData::Card(req_card) => { + PaymentMethodData::Card(req_card) => { let card = PlacetopayCard { number: req_card.card_number.clone(), expiration: req_card @@ -128,24 +135,24 @@ impl TryFrom<&PlacetopayRouterData<&types::PaymentsAuthorizeRouterData>> }, }) } - domain::PaymentMethodData::Wallet(_) - | domain::PaymentMethodData::CardRedirect(_) - | 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::MobilePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::Wallet(_) + | PaymentMethodData::CardRedirect(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::MobilePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Placetopay"), ) @@ -155,11 +162,11 @@ impl TryFrom<&PlacetopayRouterData<&types::PaymentsAuthorizeRouterData>> } } -impl TryFrom<&types::ConnectorAuthType> for PlacetopayAuth { +impl TryFrom<&ConnectorAuthType> for PlacetopayAuth { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + fn try_from(auth_type: &ConnectorAuthType) -> Result { let placetopay_auth = PlacetopayAuthType::try_from(auth_type)?; - let nonce_bytes = utils::generate_random_bytes(16); + let nonce_bytes = generate_random_bytes(16); let now = date_time::date_as_yyyymmddthhmmssmmmz() .change_context(errors::ConnectorError::RequestEncodingFailed)?; let seed = format!("{}+00:00", now.split_at(now.len() - 5).0); @@ -167,8 +174,8 @@ impl TryFrom<&types::ConnectorAuthType> for PlacetopayAuth { context.update(&nonce_bytes); context.update(seed.as_bytes()); context.update(placetopay_auth.tran_key.peek().as_bytes()); - let encoded_digest = base64::Engine::encode(&consts::BASE64_ENGINE, context.finish()); - let nonce = Secret::new(base64::Engine::encode(&consts::BASE64_ENGINE, &nonce_bytes)); + let encoded_digest = base64::Engine::encode(&BASE64_ENGINE, context.finish()); + let nonce = Secret::new(base64::Engine::encode(&BASE64_ENGINE, &nonce_bytes)); Ok(Self { login: placetopay_auth.login, tran_key: encoded_digest.into(), @@ -178,11 +185,11 @@ impl TryFrom<&types::ConnectorAuthType> for PlacetopayAuth { } } -impl TryFrom<&types::ConnectorAuthType> for PlacetopayAuthType { +impl TryFrom<&ConnectorAuthType> for PlacetopayAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { - if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { + fn try_from(auth_type: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { Ok(Self { login: api_key.to_owned(), tran_key: key1.to_owned(), @@ -244,24 +251,17 @@ pub struct PlacetopayPaymentsResponse { authorization: Option, } -impl - TryFrom< - types::ResponseRouterData, - > for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - PlacetopayPaymentsResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { Ok(Self { status: enums::AttemptStatus::from(item.response.status.status), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( item.response.internal_reference.to_string(), ), redirection_data: Box::new(None), @@ -374,15 +374,15 @@ pub struct PlacetopayRefundResponse { internal_reference: u64, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.internal_reference.to_string(), refund_status: enums::RefundStatus::from(item.response.status.status), }), @@ -398,9 +398,9 @@ pub struct PlacetopayRsyncRequest { internal_reference: u64, } -impl TryFrom<&types::RefundsRouterData> for PlacetopayRsyncRequest { +impl TryFrom<&types::RefundsRouterData> for PlacetopayRsyncRequest { type Error = error_stack::Report; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(item: &types::RefundsRouterData) -> Result { let auth = PlacetopayAuth::try_from(&item.connector_auth_type)?; let internal_reference = item .request @@ -414,15 +414,15 @@ impl TryFrom<&types::RefundsRouterData> for PlacetopayRsyncRequest { } } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.internal_reference.to_string(), refund_status: enums::RefundStatus::from(item.response.status.status), }), diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs index aaaeecb50e6c..041e519acdc6 100644 --- a/crates/hyperswitch_connectors/src/default_implementations.rs +++ b/crates/hyperswitch_connectors/src/default_implementations.rs @@ -95,10 +95,12 @@ default_imp_for_authorize_session_token!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -116,8 +118,10 @@ default_imp_for_authorize_session_token!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -160,10 +164,12 @@ default_imp_for_calculate_tax!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -181,10 +187,12 @@ default_imp_for_calculate_tax!( connectors::Multisafepay, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Nomupay, connectors::Novalnet, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Rapyd, @@ -225,10 +233,12 @@ default_imp_for_session_update!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Digitalvirgo, connectors::Dlocal, connectors::Elavon, @@ -251,8 +261,10 @@ default_imp_for_session_update!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::UnifiedAuthenticationService, connectors::Fiuu, connectors::Globepay, @@ -290,11 +302,13 @@ default_imp_for_post_session_tokens!( connectors::Bambora, connectors::Bamboraapac, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Billwerk, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Digitalvirgo, connectors::Dlocal, connectors::Elavon, @@ -317,8 +331,10 @@ default_imp_for_post_session_tokens!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Fiuu, connectors::Globepay, connectors::Gocardless, @@ -361,6 +377,7 @@ default_imp_for_complete_authorize!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Dlocal, connectors::Elavon, connectors::Fiserv, @@ -378,6 +395,7 @@ default_imp_for_complete_authorize!( connectors::Nexinets, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Rapyd, connectors::Razorpay, connectors::Redsys, @@ -416,10 +434,12 @@ default_imp_for_incremental_authorization!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -437,8 +457,10 @@ default_imp_for_incremental_authorization!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -483,10 +505,12 @@ default_imp_for_create_customer!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -505,8 +529,10 @@ default_imp_for_create_customer!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Rapyd, @@ -552,6 +578,7 @@ default_imp_for_connector_redirect_response!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Dlocal, connectors::Elavon, @@ -570,6 +597,7 @@ default_imp_for_connector_redirect_response!( connectors::Nomupay, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Rapyd, @@ -609,10 +637,12 @@ default_imp_for_pre_processing_steps!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -628,8 +658,10 @@ default_imp_for_pre_processing_steps!( connectors::Nomupay, connectors::Novalnet, connectors::Nexinets, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -673,10 +705,12 @@ default_imp_for_post_processing_steps!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -694,8 +728,10 @@ default_imp_for_post_processing_steps!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -740,10 +776,12 @@ default_imp_for_approve!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -761,8 +799,10 @@ default_imp_for_approve!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -807,10 +847,12 @@ default_imp_for_reject!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -828,8 +870,10 @@ default_imp_for_reject!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -874,10 +918,12 @@ default_imp_for_webhook_source_verification!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -895,8 +941,10 @@ default_imp_for_webhook_source_verification!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -942,10 +990,12 @@ default_imp_for_accept_dispute!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -963,8 +1013,10 @@ default_imp_for_accept_dispute!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1009,10 +1061,12 @@ default_imp_for_submit_evidence!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1030,8 +1084,10 @@ default_imp_for_submit_evidence!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1076,10 +1132,12 @@ default_imp_for_defend_dispute!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1097,8 +1155,10 @@ default_imp_for_defend_dispute!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1152,10 +1212,12 @@ default_imp_for_file_upload!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1173,8 +1235,10 @@ default_imp_for_file_upload!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1212,9 +1276,11 @@ default_imp_for_payouts!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Cryptopay, + connectors::Datatrans, connectors::Coinbase, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1233,10 +1299,12 @@ default_imp_for_payouts!( connectors::Multisafepay, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Nomupay, connectors::Novalnet, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Rapyd, @@ -1280,10 +1348,12 @@ default_imp_for_payouts_create!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1301,8 +1371,10 @@ default_imp_for_payouts_create!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1349,10 +1421,12 @@ default_imp_for_payouts_retrieve!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1370,8 +1444,10 @@ default_imp_for_payouts_retrieve!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1418,10 +1494,12 @@ default_imp_for_payouts_eligibility!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1439,8 +1517,10 @@ default_imp_for_payouts_eligibility!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1487,10 +1567,12 @@ default_imp_for_payouts_fulfill!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1508,8 +1590,10 @@ default_imp_for_payouts_fulfill!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1556,10 +1640,12 @@ default_imp_for_payouts_cancel!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1577,8 +1663,10 @@ default_imp_for_payouts_cancel!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1625,10 +1713,12 @@ default_imp_for_payouts_quote!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1646,8 +1736,10 @@ default_imp_for_payouts_quote!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1694,10 +1786,12 @@ default_imp_for_payouts_recipient!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1715,8 +1809,10 @@ default_imp_for_payouts_recipient!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1763,10 +1859,12 @@ default_imp_for_payouts_recipient_account!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1784,8 +1882,10 @@ default_imp_for_payouts_recipient_account!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1832,10 +1932,12 @@ default_imp_for_frm_sale!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1853,8 +1955,10 @@ default_imp_for_frm_sale!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1901,10 +2005,12 @@ default_imp_for_frm_checkout!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1922,8 +2028,10 @@ default_imp_for_frm_checkout!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1970,10 +2078,12 @@ default_imp_for_frm_transaction!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1991,8 +2101,10 @@ default_imp_for_frm_transaction!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -2039,10 +2151,12 @@ default_imp_for_frm_fulfillment!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -2060,8 +2174,10 @@ default_imp_for_frm_fulfillment!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -2108,10 +2224,12 @@ default_imp_for_frm_record_return!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -2129,8 +2247,10 @@ default_imp_for_frm_record_return!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -2174,10 +2294,12 @@ default_imp_for_revoking_mandates!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -2195,8 +2317,10 @@ default_imp_for_revoking_mandates!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, diff --git a/crates/hyperswitch_connectors/src/default_implementations_v2.rs b/crates/hyperswitch_connectors/src/default_implementations_v2.rs index 10a5fea8c401..33c45a542257 100644 --- a/crates/hyperswitch_connectors/src/default_implementations_v2.rs +++ b/crates/hyperswitch_connectors/src/default_implementations_v2.rs @@ -211,10 +211,12 @@ default_imp_for_new_connector_integration_payment!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -232,8 +234,10 @@ default_imp_for_new_connector_integration_payment!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -279,10 +283,12 @@ default_imp_for_new_connector_integration_refund!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -300,8 +306,10 @@ default_imp_for_new_connector_integration_refund!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -342,10 +350,12 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -363,8 +373,10 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -411,10 +423,12 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -432,8 +446,10 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -479,10 +495,12 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -500,8 +518,10 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -547,10 +567,12 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -568,8 +590,10 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -625,10 +649,12 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -646,8 +672,10 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -695,10 +723,12 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -716,8 +746,10 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -765,10 +797,12 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -786,8 +820,10 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -835,10 +871,12 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -856,8 +894,10 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -905,10 +945,12 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -926,8 +968,10 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -975,10 +1019,12 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -996,8 +1042,10 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1045,10 +1093,12 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1066,8 +1116,10 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1115,10 +1167,12 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1136,8 +1190,10 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1185,10 +1241,12 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1206,8 +1264,10 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1253,10 +1313,12 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1274,8 +1336,10 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1323,10 +1387,12 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1344,8 +1410,10 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1393,10 +1461,12 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1414,8 +1484,10 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1463,10 +1535,12 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1484,8 +1558,10 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1533,10 +1609,12 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1554,8 +1632,10 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1603,10 +1683,12 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1624,8 +1706,10 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, @@ -1670,10 +1754,12 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Bamboraapac, connectors::Billwerk, connectors::Bitpay, + connectors::Bluesnap, connectors::Boku, connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, connectors::Dlocal, @@ -1691,8 +1777,10 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Novalnet, connectors::Nexinets, connectors::Nexixpay, + connectors::Paybox, connectors::Payeezy, connectors::Payu, + connectors::Placetopay, connectors::Powertranz, connectors::Prophetpay, connectors::Mollie, diff --git a/crates/hyperswitch_connectors/src/types.rs b/crates/hyperswitch_connectors/src/types.rs index 0d7ecfc36433..05ef62d78282 100644 --- a/crates/hyperswitch_connectors/src/types.rs +++ b/crates/hyperswitch_connectors/src/types.rs @@ -1,9 +1,9 @@ use hyperswitch_domain_models::{ router_data::{AccessToken, RouterData}, - router_flow_types::{AccessTokenAuth, Capture, PSync, PreProcessing, Void}, + router_flow_types::{AccessTokenAuth, Capture, PSync, PreProcessing, Session, Void}, router_request_types::{ AccessTokenRequestData, PaymentsCancelData, PaymentsCaptureData, PaymentsPreProcessingData, - PaymentsSyncData, RefundsData, + PaymentsSessionData, PaymentsSyncData, RefundsData, }, router_response_types::{PaymentsResponseData, RefundsResponseData}, }; @@ -22,6 +22,8 @@ pub(crate) type PaymentsCancelResponseRouterData = ResponseRouterData; pub(crate) type PaymentsPreprocessingResponseRouterData = ResponseRouterData; +pub(crate) type PaymentsSessionResponseRouterData = + ResponseRouterData; // TODO: Remove `ResponseRouterData` from router crate after all the related type aliases are moved to this crate. pub struct ResponseRouterData { diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 27e80fafa92e..6dce48e69965 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -17,7 +17,7 @@ use common_utils::{ use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ address::{Address, AddressDetails, PhoneDetails}, - payment_method_data::{Card, PaymentMethodData}, + payment_method_data::{self, Card, PaymentMethodData}, router_data::{ ApplePayPredecryptData, ErrorResponse, PaymentMethodToken, RecurringMandatePaymentData, }, @@ -83,6 +83,102 @@ pub(crate) fn to_currency_base_unit( .change_context(errors::ConnectorError::ParsingFailed) } +pub(crate) fn to_currency_lower_unit( + amount: String, + currency: enums::Currency, +) -> Result> { + currency + .to_currency_lower_unit(amount) + .change_context(errors::ConnectorError::ResponseHandlingFailed) +} + +pub trait ConnectorErrorTypeMapping { + fn get_connector_error_type( + &self, + _error_code: String, + _error_message: String, + ) -> ConnectorErrorType { + ConnectorErrorType::UnknownError + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ErrorCodeAndMessage { + pub error_code: String, + pub error_message: String, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] +//Priority of connector_error_type +pub enum ConnectorErrorType { + UserError = 2, + BusinessError = 3, + TechnicalError = 4, + UnknownError = 1, +} + +pub(crate) fn get_error_code_error_message_based_on_priority( + connector: impl ConnectorErrorTypeMapping, + error_list: Vec, +) -> Option { + let error_type_list = error_list + .iter() + .map(|error| { + connector + .get_connector_error_type(error.error_code.clone(), error.error_message.clone()) + }) + .collect::>(); + let mut error_zip_list = error_list + .iter() + .zip(error_type_list.iter()) + .collect::>(); + error_zip_list.sort_by_key(|&(_, error_type)| error_type); + error_zip_list + .first() + .map(|&(error_code_message, _)| error_code_message) + .cloned() +} + +#[derive(Clone, Debug, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GooglePayWalletData { + #[serde(rename = "type")] + pub pm_type: String, + pub description: String, + pub info: GooglePayPaymentMethodInfo, + pub tokenization_data: GpayTokenizationData, +} + +#[derive(Clone, Debug, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GooglePayPaymentMethodInfo { + pub card_network: String, + pub card_details: String, +} + +#[derive(Clone, Debug, serde::Serialize)] +pub struct GpayTokenizationData { + #[serde(rename = "type")] + pub token_type: String, + pub token: Secret, +} + +impl From for GooglePayWalletData { + fn from(data: payment_method_data::GooglePayWalletData) -> Self { + Self { + pm_type: data.pm_type, + description: data.description, + info: GooglePayPaymentMethodInfo { + card_network: data.info.card_network, + card_details: data.info.card_details, + }, + tokenization_data: GpayTokenizationData { + token_type: data.tokenization_data.token_type, + token: Secret::new(data.tokenization_data.token), + }, + } + } +} pub(crate) fn get_amount_as_f64( currency_unit: &api::CurrencyUnit, amount: i64, @@ -118,6 +214,12 @@ where json.parse_value(std::any::type_name::()).switch() } +pub(crate) fn generate_random_bytes(length: usize) -> Vec { + // returns random bytes of length n + let mut rng = rand::thread_rng(); + (0..length).map(|_| rand::Rng::gen(&mut rng)).collect() +} + pub(crate) fn missing_field_err( message: &'static str, ) -> Box error_stack::Report + 'static> { @@ -1178,10 +1280,11 @@ pub trait PaymentsAuthorizeRequestData { fn get_metadata_as_object(&self) -> Option; fn get_authentication_data(&self) -> Result; fn get_customer_name(&self) -> Result, Error>; + fn get_connector_mandate_request_reference_id(&self) -> Result; fn get_card_holder_name_from_additional_payment_method_data( &self, ) -> Result, Error>; - fn get_connector_mandate_request_reference_id(&self) -> Result; + fn is_cit_mandate_payment(&self) -> bool; } impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { @@ -1376,6 +1479,12 @@ impl PaymentsAuthorizeRequestData for PaymentsAuthorizeData { }) .ok_or_else(missing_field_err("connector_mandate_request_reference_id")) } + fn is_cit_mandate_payment(&self) -> bool { + (self.customer_acceptance.is_some() || self.setup_mandate_details.is_some()) + && self.setup_future_usage.map_or(false, |setup_future_usage| { + setup_future_usage == FutureUsage::OffSession + }) + } } pub trait PaymentsCaptureRequestData { @@ -1538,6 +1647,7 @@ pub trait PaymentsCompleteAuthorizeRequestData { fn get_complete_authorize_url(&self) -> Result; fn is_mandate_payment(&self) -> bool; fn get_connector_mandate_request_reference_id(&self) -> Result; + fn is_cit_mandate_payment(&self) -> bool; } impl PaymentsCompleteAuthorizeRequestData for CompleteAuthorizeData { @@ -1594,6 +1704,12 @@ impl PaymentsCompleteAuthorizeRequestData for CompleteAuthorizeData { }) .ok_or_else(missing_field_err("connector_mandate_request_reference_id")) } + fn is_cit_mandate_payment(&self) -> bool { + (self.customer_acceptance.is_some() || self.setup_mandate_details.is_some()) + && self.setup_future_usage.map_or(false, |setup_future_usage| { + setup_future_usage == FutureUsage::OffSession + }) + } } pub trait AddressData { fn get_optional_full_name(&self) -> Option>; @@ -1725,7 +1841,7 @@ pub trait CryptoData { fn get_pay_currency(&self) -> Result; } -impl CryptoData for hyperswitch_domain_models::payment_method_data::CryptoData { +impl CryptoData for payment_method_data::CryptoData { fn get_pay_currency(&self) -> Result { self.pay_currency .clone() @@ -2054,187 +2170,183 @@ impl From for PaymentMethodDataType { match pm_data { PaymentMethodData::Card(_) => Self::Card, PaymentMethodData::NetworkToken(_) => Self::NetworkToken, - PaymentMethodData::CardDetailsForNetworkTransactionId(_) => Self::NetworkTransactionIdAndCardDetails, - PaymentMethodData::CardRedirect(card_redirect_data) => { - match card_redirect_data { - hyperswitch_domain_models::payment_method_data::CardRedirectData::Knet {} => Self::Knet, - hyperswitch_domain_models::payment_method_data::CardRedirectData::Benefit {} => Self::Benefit, - hyperswitch_domain_models::payment_method_data::CardRedirectData::MomoAtm {} => Self::MomoAtm, - hyperswitch_domain_models::payment_method_data::CardRedirectData::CardRedirect {} => Self::CardRedirect, - } + PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + Self::NetworkTransactionIdAndCardDetails } + PaymentMethodData::CardRedirect(card_redirect_data) => match card_redirect_data { + payment_method_data::CardRedirectData::Knet {} => Self::Knet, + payment_method_data::CardRedirectData::Benefit {} => Self::Benefit, + payment_method_data::CardRedirectData::MomoAtm {} => Self::MomoAtm, + payment_method_data::CardRedirectData::CardRedirect {} => Self::CardRedirect, + }, PaymentMethodData::Wallet(wallet_data) => match wallet_data { - hyperswitch_domain_models::payment_method_data::WalletData::AliPayQr(_) => Self::AliPayQr, - hyperswitch_domain_models::payment_method_data::WalletData::AliPayRedirect(_) => Self::AliPayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::AliPayHkRedirect(_) => Self::AliPayHkRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::MomoRedirect(_) => Self::MomoRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::KakaoPayRedirect(_) => Self::KakaoPayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::GoPayRedirect(_) => Self::GoPayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::GcashRedirect(_) => Self::GcashRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::ApplePay(_) => Self::ApplePay, - hyperswitch_domain_models::payment_method_data::WalletData::ApplePayRedirect(_) => Self::ApplePayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::ApplePayThirdPartySdk(_) => { + payment_method_data::WalletData::AliPayQr(_) => Self::AliPayQr, + payment_method_data::WalletData::AliPayRedirect(_) => Self::AliPayRedirect, + payment_method_data::WalletData::AliPayHkRedirect(_) => Self::AliPayHkRedirect, + payment_method_data::WalletData::MomoRedirect(_) => Self::MomoRedirect, + payment_method_data::WalletData::KakaoPayRedirect(_) => Self::KakaoPayRedirect, + payment_method_data::WalletData::GoPayRedirect(_) => Self::GoPayRedirect, + payment_method_data::WalletData::GcashRedirect(_) => Self::GcashRedirect, + payment_method_data::WalletData::ApplePay(_) => Self::ApplePay, + payment_method_data::WalletData::ApplePayRedirect(_) => Self::ApplePayRedirect, + payment_method_data::WalletData::ApplePayThirdPartySdk(_) => { Self::ApplePayThirdPartySdk } - hyperswitch_domain_models::payment_method_data::WalletData::DanaRedirect {} => Self::DanaRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::GooglePay(_) => Self::GooglePay, - hyperswitch_domain_models::payment_method_data::WalletData::GooglePayRedirect(_) => Self::GooglePayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::GooglePayThirdPartySdk(_) => { + payment_method_data::WalletData::DanaRedirect {} => Self::DanaRedirect, + payment_method_data::WalletData::GooglePay(_) => Self::GooglePay, + payment_method_data::WalletData::GooglePayRedirect(_) => Self::GooglePayRedirect, + payment_method_data::WalletData::GooglePayThirdPartySdk(_) => { Self::GooglePayThirdPartySdk } - hyperswitch_domain_models::payment_method_data::WalletData::MbWayRedirect(_) => Self::MbWayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::MobilePayRedirect(_) => Self::MobilePayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::PaypalRedirect(_) => Self::PaypalRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::PaypalSdk(_) => Self::PaypalSdk, - hyperswitch_domain_models::payment_method_data::WalletData::Paze(_) => Self::Paze, - hyperswitch_domain_models::payment_method_data::WalletData::SamsungPay(_) => Self::SamsungPay, - hyperswitch_domain_models::payment_method_data::WalletData::TwintRedirect {} => Self::TwintRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::VippsRedirect {} => Self::VippsRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::TouchNGoRedirect(_) => Self::TouchNGoRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::WeChatPayRedirect(_) => Self::WeChatPayRedirect, - hyperswitch_domain_models::payment_method_data::WalletData::WeChatPayQr(_) => Self::WeChatPayQr, - hyperswitch_domain_models::payment_method_data::WalletData::CashappQr(_) => Self::CashappQr, - hyperswitch_domain_models::payment_method_data::WalletData::SwishQr(_) => Self::SwishQr, - hyperswitch_domain_models::payment_method_data::WalletData::Mifinity(_) => Self::Mifinity, + payment_method_data::WalletData::MbWayRedirect(_) => Self::MbWayRedirect, + payment_method_data::WalletData::MobilePayRedirect(_) => Self::MobilePayRedirect, + payment_method_data::WalletData::PaypalRedirect(_) => Self::PaypalRedirect, + payment_method_data::WalletData::PaypalSdk(_) => Self::PaypalSdk, + payment_method_data::WalletData::Paze(_) => Self::Paze, + payment_method_data::WalletData::SamsungPay(_) => Self::SamsungPay, + payment_method_data::WalletData::TwintRedirect {} => Self::TwintRedirect, + payment_method_data::WalletData::VippsRedirect {} => Self::VippsRedirect, + payment_method_data::WalletData::TouchNGoRedirect(_) => Self::TouchNGoRedirect, + payment_method_data::WalletData::WeChatPayRedirect(_) => Self::WeChatPayRedirect, + payment_method_data::WalletData::WeChatPayQr(_) => Self::WeChatPayQr, + payment_method_data::WalletData::CashappQr(_) => Self::CashappQr, + payment_method_data::WalletData::SwishQr(_) => Self::SwishQr, + payment_method_data::WalletData::Mifinity(_) => Self::Mifinity, }, PaymentMethodData::PayLater(pay_later_data) => match pay_later_data { - hyperswitch_domain_models::payment_method_data::PayLaterData::KlarnaRedirect { .. } => Self::KlarnaRedirect, - hyperswitch_domain_models::payment_method_data::PayLaterData::KlarnaSdk { .. } => Self::KlarnaSdk, - hyperswitch_domain_models::payment_method_data::PayLaterData::AffirmRedirect {} => Self::AffirmRedirect, - hyperswitch_domain_models::payment_method_data::PayLaterData::AfterpayClearpayRedirect { .. } => { + payment_method_data::PayLaterData::KlarnaRedirect { .. } => Self::KlarnaRedirect, + payment_method_data::PayLaterData::KlarnaSdk { .. } => Self::KlarnaSdk, + payment_method_data::PayLaterData::AffirmRedirect {} => Self::AffirmRedirect, + payment_method_data::PayLaterData::AfterpayClearpayRedirect { .. } => { Self::AfterpayClearpayRedirect } - hyperswitch_domain_models::payment_method_data::PayLaterData::PayBrightRedirect {} => Self::PayBrightRedirect, - hyperswitch_domain_models::payment_method_data::PayLaterData::WalleyRedirect {} => Self::WalleyRedirect, - hyperswitch_domain_models::payment_method_data::PayLaterData::AlmaRedirect {} => Self::AlmaRedirect, - hyperswitch_domain_models::payment_method_data::PayLaterData::AtomeRedirect {} => Self::AtomeRedirect, + payment_method_data::PayLaterData::PayBrightRedirect {} => Self::PayBrightRedirect, + payment_method_data::PayLaterData::WalleyRedirect {} => Self::WalleyRedirect, + payment_method_data::PayLaterData::AlmaRedirect {} => Self::AlmaRedirect, + payment_method_data::PayLaterData::AtomeRedirect {} => Self::AtomeRedirect, }, - PaymentMethodData::BankRedirect(bank_redirect_data) => { - match bank_redirect_data { - hyperswitch_domain_models::payment_method_data::BankRedirectData::BancontactCard { .. } => { - Self::BancontactCard - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::Bizum {} => Self::Bizum, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Blik { .. } => Self::Blik, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Eps { .. } => Self::Eps, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Giropay { .. } => Self::Giropay, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Ideal { .. } => Self::Ideal, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Interac { .. } => Self::Interac, - hyperswitch_domain_models::payment_method_data::BankRedirectData::OnlineBankingCzechRepublic { .. } => { - Self::OnlineBankingCzechRepublic - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::OnlineBankingFinland { .. } => { - Self::OnlineBankingFinland - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::OnlineBankingPoland { .. } => { - Self::OnlineBankingPoland - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::OnlineBankingSlovakia { .. } => { - Self::OnlineBankingSlovakia - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::OpenBankingUk { .. } => Self::OpenBankingUk, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Przelewy24 { .. } => Self::Przelewy24, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Sofort { .. } => Self::Sofort, - hyperswitch_domain_models::payment_method_data::BankRedirectData::Trustly { .. } => Self::Trustly, - hyperswitch_domain_models::payment_method_data::BankRedirectData::OnlineBankingFpx { .. } => { - Self::OnlineBankingFpx - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::OnlineBankingThailand { .. } => { - Self::OnlineBankingThailand - } - hyperswitch_domain_models::payment_method_data::BankRedirectData::LocalBankRedirect { } => { - Self::LocalBankRedirect - } + PaymentMethodData::BankRedirect(bank_redirect_data) => match bank_redirect_data { + payment_method_data::BankRedirectData::BancontactCard { .. } => { + Self::BancontactCard } - } - PaymentMethodData::BankDebit(bank_debit_data) => { - match bank_debit_data { - hyperswitch_domain_models::payment_method_data::BankDebitData::AchBankDebit { .. } => Self::AchBankDebit, - hyperswitch_domain_models::payment_method_data::BankDebitData::SepaBankDebit { .. } => Self::SepaBankDebit, - hyperswitch_domain_models::payment_method_data::BankDebitData::BecsBankDebit { .. } => Self::BecsBankDebit, - hyperswitch_domain_models::payment_method_data::BankDebitData::BacsBankDebit { .. } => Self::BacsBankDebit, + payment_method_data::BankRedirectData::Bizum {} => Self::Bizum, + payment_method_data::BankRedirectData::Blik { .. } => Self::Blik, + payment_method_data::BankRedirectData::Eps { .. } => Self::Eps, + payment_method_data::BankRedirectData::Giropay { .. } => Self::Giropay, + payment_method_data::BankRedirectData::Ideal { .. } => Self::Ideal, + payment_method_data::BankRedirectData::Interac { .. } => Self::Interac, + payment_method_data::BankRedirectData::OnlineBankingCzechRepublic { .. } => { + Self::OnlineBankingCzechRepublic } - } - PaymentMethodData::BankTransfer(bank_transfer_data) => { - match *bank_transfer_data { - hyperswitch_domain_models::payment_method_data::BankTransferData::AchBankTransfer { .. } => { - Self::AchBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::SepaBankTransfer { .. } => { - Self::SepaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::BacsBankTransfer { .. } => { - Self::BacsBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::MultibancoBankTransfer { .. } => { - Self::MultibancoBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::PermataBankTransfer { .. } => { - Self::PermataBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::BcaBankTransfer { .. } => { - Self::BcaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::BniVaBankTransfer { .. } => { - Self::BniVaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::BriVaBankTransfer { .. } => { - Self::BriVaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::CimbVaBankTransfer { .. } => { - Self::CimbVaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::DanamonVaBankTransfer { .. } => { - Self::DanamonVaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::MandiriVaBankTransfer { .. } => { - Self::MandiriVaBankTransfer - } - hyperswitch_domain_models::payment_method_data::BankTransferData::Pix { .. } => Self::Pix, - hyperswitch_domain_models::payment_method_data::BankTransferData::Pse {} => Self::Pse, - hyperswitch_domain_models::payment_method_data::BankTransferData::LocalBankTransfer { .. } => { - Self::LocalBankTransfer - } + payment_method_data::BankRedirectData::OnlineBankingFinland { .. } => { + Self::OnlineBankingFinland } - } + payment_method_data::BankRedirectData::OnlineBankingPoland { .. } => { + Self::OnlineBankingPoland + } + payment_method_data::BankRedirectData::OnlineBankingSlovakia { .. } => { + Self::OnlineBankingSlovakia + } + payment_method_data::BankRedirectData::OpenBankingUk { .. } => Self::OpenBankingUk, + payment_method_data::BankRedirectData::Przelewy24 { .. } => Self::Przelewy24, + payment_method_data::BankRedirectData::Sofort { .. } => Self::Sofort, + payment_method_data::BankRedirectData::Trustly { .. } => Self::Trustly, + payment_method_data::BankRedirectData::OnlineBankingFpx { .. } => { + Self::OnlineBankingFpx + } + payment_method_data::BankRedirectData::OnlineBankingThailand { .. } => { + Self::OnlineBankingThailand + } + payment_method_data::BankRedirectData::LocalBankRedirect {} => { + Self::LocalBankRedirect + } + }, + PaymentMethodData::BankDebit(bank_debit_data) => match bank_debit_data { + payment_method_data::BankDebitData::AchBankDebit { .. } => Self::AchBankDebit, + payment_method_data::BankDebitData::SepaBankDebit { .. } => Self::SepaBankDebit, + payment_method_data::BankDebitData::BecsBankDebit { .. } => Self::BecsBankDebit, + payment_method_data::BankDebitData::BacsBankDebit { .. } => Self::BacsBankDebit, + }, + PaymentMethodData::BankTransfer(bank_transfer_data) => match *bank_transfer_data { + payment_method_data::BankTransferData::AchBankTransfer { .. } => { + Self::AchBankTransfer + } + payment_method_data::BankTransferData::SepaBankTransfer { .. } => { + Self::SepaBankTransfer + } + payment_method_data::BankTransferData::BacsBankTransfer { .. } => { + Self::BacsBankTransfer + } + payment_method_data::BankTransferData::MultibancoBankTransfer { .. } => { + Self::MultibancoBankTransfer + } + payment_method_data::BankTransferData::PermataBankTransfer { .. } => { + Self::PermataBankTransfer + } + payment_method_data::BankTransferData::BcaBankTransfer { .. } => { + Self::BcaBankTransfer + } + payment_method_data::BankTransferData::BniVaBankTransfer { .. } => { + Self::BniVaBankTransfer + } + payment_method_data::BankTransferData::BriVaBankTransfer { .. } => { + Self::BriVaBankTransfer + } + payment_method_data::BankTransferData::CimbVaBankTransfer { .. } => { + Self::CimbVaBankTransfer + } + payment_method_data::BankTransferData::DanamonVaBankTransfer { .. } => { + Self::DanamonVaBankTransfer + } + payment_method_data::BankTransferData::MandiriVaBankTransfer { .. } => { + Self::MandiriVaBankTransfer + } + payment_method_data::BankTransferData::Pix { .. } => Self::Pix, + payment_method_data::BankTransferData::Pse {} => Self::Pse, + payment_method_data::BankTransferData::LocalBankTransfer { .. } => { + Self::LocalBankTransfer + } + }, PaymentMethodData::Crypto(_) => Self::Crypto, PaymentMethodData::MandatePayment => Self::MandatePayment, PaymentMethodData::Reward => Self::Reward, PaymentMethodData::Upi(_) => Self::Upi, PaymentMethodData::Voucher(voucher_data) => match voucher_data { - hyperswitch_domain_models::payment_method_data::VoucherData::Boleto(_) => Self::Boleto, - hyperswitch_domain_models::payment_method_data::VoucherData::Efecty => Self::Efecty, - hyperswitch_domain_models::payment_method_data::VoucherData::PagoEfectivo => Self::PagoEfectivo, - hyperswitch_domain_models::payment_method_data::VoucherData::RedCompra => Self::RedCompra, - hyperswitch_domain_models::payment_method_data::VoucherData::RedPagos => Self::RedPagos, - hyperswitch_domain_models::payment_method_data::VoucherData::Alfamart(_) => Self::Alfamart, - hyperswitch_domain_models::payment_method_data::VoucherData::Indomaret(_) => Self::Indomaret, - hyperswitch_domain_models::payment_method_data::VoucherData::Oxxo => Self::Oxxo, - hyperswitch_domain_models::payment_method_data::VoucherData::SevenEleven(_) => Self::SevenEleven, - hyperswitch_domain_models::payment_method_data::VoucherData::Lawson(_) => Self::Lawson, - hyperswitch_domain_models::payment_method_data::VoucherData::MiniStop(_) => Self::MiniStop, - hyperswitch_domain_models::payment_method_data::VoucherData::FamilyMart(_) => Self::FamilyMart, - hyperswitch_domain_models::payment_method_data::VoucherData::Seicomart(_) => Self::Seicomart, - hyperswitch_domain_models::payment_method_data::VoucherData::PayEasy(_) => Self::PayEasy, - }, - PaymentMethodData::RealTimePayment(real_time_payment_data) => match *real_time_payment_data{ - hyperswitch_domain_models::payment_method_data::RealTimePaymentData::DuitNow { } => Self::DuitNow, - hyperswitch_domain_models::payment_method_data::RealTimePaymentData::Fps { } => Self::Fps, - hyperswitch_domain_models::payment_method_data::RealTimePaymentData::PromptPay { } => Self::PromptPay, - hyperswitch_domain_models::payment_method_data::RealTimePaymentData::VietQr { } => Self::VietQr, + payment_method_data::VoucherData::Boleto(_) => Self::Boleto, + payment_method_data::VoucherData::Efecty => Self::Efecty, + payment_method_data::VoucherData::PagoEfectivo => Self::PagoEfectivo, + payment_method_data::VoucherData::RedCompra => Self::RedCompra, + payment_method_data::VoucherData::RedPagos => Self::RedPagos, + payment_method_data::VoucherData::Alfamart(_) => Self::Alfamart, + payment_method_data::VoucherData::Indomaret(_) => Self::Indomaret, + payment_method_data::VoucherData::Oxxo => Self::Oxxo, + payment_method_data::VoucherData::SevenEleven(_) => Self::SevenEleven, + payment_method_data::VoucherData::Lawson(_) => Self::Lawson, + payment_method_data::VoucherData::MiniStop(_) => Self::MiniStop, + payment_method_data::VoucherData::FamilyMart(_) => Self::FamilyMart, + payment_method_data::VoucherData::Seicomart(_) => Self::Seicomart, + payment_method_data::VoucherData::PayEasy(_) => Self::PayEasy, }, - PaymentMethodData::GiftCard(gift_card_data) => { - match *gift_card_data { - hyperswitch_domain_models::payment_method_data::GiftCardData::Givex(_) => Self::Givex, - hyperswitch_domain_models::payment_method_data::GiftCardData::PaySafeCard {} => Self::PaySafeCar, + PaymentMethodData::RealTimePayment(real_time_payment_data) => { + match *real_time_payment_data { + payment_method_data::RealTimePaymentData::DuitNow {} => Self::DuitNow, + payment_method_data::RealTimePaymentData::Fps {} => Self::Fps, + payment_method_data::RealTimePaymentData::PromptPay {} => Self::PromptPay, + payment_method_data::RealTimePaymentData::VietQr {} => Self::VietQr, } } + PaymentMethodData::GiftCard(gift_card_data) => match *gift_card_data { + payment_method_data::GiftCardData::Givex(_) => Self::Givex, + payment_method_data::GiftCardData::PaySafeCard {} => Self::PaySafeCar, + }, PaymentMethodData::CardToken(_) => Self::CardToken, PaymentMethodData::OpenBanking(data) => match data { - hyperswitch_domain_models::payment_method_data::OpenBankingData::OpenBankingPIS { } => Self::OpenBanking + payment_method_data::OpenBankingData::OpenBankingPIS {} => Self::OpenBanking, }, PaymentMethodData::MobilePayment(mobile_payment_data) => match mobile_payment_data { - hyperswitch_domain_models::payment_method_data::MobilePaymentData::DirectCarrierBilling { .. } => Self::DirectCarrierBilling, + payment_method_data::MobilePaymentData::DirectCarrierBilling { .. } => { + Self::DirectCarrierBilling + } }, } } @@ -2243,7 +2355,7 @@ pub trait ApplePay { fn get_applepay_decoded_payment_data(&self) -> Result, Error>; } -impl ApplePay for hyperswitch_domain_models::payment_method_data::ApplePayWalletData { +impl ApplePay for payment_method_data::ApplePayWalletData { fn get_applepay_decoded_payment_data(&self) -> Result, Error> { let token = Secret::new( String::from_utf8(BASE64_ENGINE.decode(&self.payment_data).change_context( @@ -2267,7 +2379,7 @@ pub trait WalletData { fn get_encoded_wallet_token(&self) -> Result; } -impl WalletData for hyperswitch_domain_models::payment_method_data::WalletData { +impl WalletData for payment_method_data::WalletData { fn get_wallet_token(&self) -> Result, Error> { match self { Self::GooglePay(data) => Ok(Secret::new(data.tokenization_data.token.clone())), diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index 04e972e51871..3d3c42d07961 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -3,11 +3,9 @@ pub mod adyen; pub mod adyenplatform; pub mod authorizedotnet; pub mod bankofamerica; -pub mod bluesnap; pub mod braintree; pub mod checkout; pub mod cybersource; -pub mod datatrans; #[cfg(feature = "dummy_connector")] pub mod dummyconnector; pub mod ebanx; @@ -23,11 +21,9 @@ pub mod noon; pub mod nuvei; pub mod opayo; pub mod opennode; -pub mod paybox; pub mod payme; pub mod payone; pub mod paypal; -pub mod placetopay; pub mod plaid; pub mod riskified; pub mod signifyd; @@ -42,18 +38,19 @@ pub mod wise; pub use hyperswitch_connectors::connectors::{ airwallex, airwallex::Airwallex, amazonpay, amazonpay::Amazonpay, bambora, bambora::Bambora, bamboraapac, bamboraapac::Bamboraapac, billwerk, billwerk::Billwerk, bitpay, bitpay::Bitpay, - boku, boku::Boku, cashtocode, cashtocode::Cashtocode, coinbase, coinbase::Coinbase, cryptopay, - cryptopay::Cryptopay, 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, payeezy, payeezy::Payeezy, payu, - payu::Payu, 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, + 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, + 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, unified_authentication_service::UnifiedAuthenticationService, volt, volt::Volt, worldline, worldline::Worldline, worldpay, worldpay::Worldpay, xendit, xendit::Xendit, zen, zen::Zen, zsl, zsl::Zsl, @@ -63,12 +60,11 @@ pub use hyperswitch_connectors::connectors::{ pub use self::dummyconnector::DummyConnector; pub use self::{ aci::Aci, adyen::Adyen, adyenplatform::Adyenplatform, authorizedotnet::Authorizedotnet, - bankofamerica::Bankofamerica, bluesnap::Bluesnap, braintree::Braintree, checkout::Checkout, - cybersource::Cybersource, datatrans::Datatrans, ebanx::Ebanx, globalpay::Globalpay, - gpayments::Gpayments, iatapay::Iatapay, itaubank::Itaubank, klarna::Klarna, mifinity::Mifinity, - netcetera::Netcetera, nmi::Nmi, noon::Noon, nuvei::Nuvei, opayo::Opayo, opennode::Opennode, - paybox::Paybox, payme::Payme, payone::Payone, paypal::Paypal, placetopay::Placetopay, - plaid::Plaid, riskified::Riskified, signifyd::Signifyd, stripe::Stripe, - threedsecureio::Threedsecureio, trustpay::Trustpay, wellsfargo::Wellsfargo, + bankofamerica::Bankofamerica, braintree::Braintree, checkout::Checkout, + cybersource::Cybersource, ebanx::Ebanx, globalpay::Globalpay, gpayments::Gpayments, + iatapay::Iatapay, itaubank::Itaubank, klarna::Klarna, mifinity::Mifinity, netcetera::Netcetera, + nmi::Nmi, noon::Noon, nuvei::Nuvei, opayo::Opayo, opennode::Opennode, payme::Payme, + payone::Payone, paypal::Paypal, plaid::Plaid, riskified::Riskified, signifyd::Signifyd, + stripe::Stripe, threedsecureio::Threedsecureio, trustpay::Trustpay, wellsfargo::Wellsfargo, wellsfargopayout::Wellsfargopayout, wise::Wise, }; diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs index bf78424c9d24..3d3b3b9814d7 100644 --- a/crates/router/src/consts.rs +++ b/crates/router/src/consts.rs @@ -54,10 +54,6 @@ pub(crate) const BASE64_ENGINE: base64::engine::GeneralPurpose = consts::BASE64_ pub(crate) const API_KEY_LENGTH: usize = 64; -// Apple Pay validation url -pub(crate) const APPLEPAY_VALIDATION_URL: &str = - "https://apple-pay-gateway-cert.apple.com/paymentservices/startSession"; - // OID (Object Identifier) for the merchant ID field extension. pub(crate) const MERCHANT_ID_FIELD_EXTENSION_ID: &str = "1.2.840.113635.100.6.32"; 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 8725470e2599..c9da7bb1fd95 100644 --- a/crates/router/src/core/payments/connector_integration_v2_impls.rs +++ b/crates/router/src/core/payments/connector_integration_v2_impls.rs @@ -695,11 +695,9 @@ default_imp_for_new_connector_integration_payment!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -713,11 +711,9 @@ default_imp_for_new_connector_integration_payment!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -751,11 +747,9 @@ default_imp_for_new_connector_integration_refund!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -769,11 +763,9 @@ default_imp_for_new_connector_integration_refund!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -801,11 +793,9 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -819,11 +809,9 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -873,11 +861,9 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -891,11 +877,9 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -927,11 +911,9 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -945,11 +927,9 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -965,11 +945,9 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -983,11 +961,9 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1030,11 +1006,9 @@ default_imp_for_new_connector_integration_file_upload!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1048,11 +1022,9 @@ default_imp_for_new_connector_integration_file_upload!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1091,7 +1063,6 @@ default_imp_for_new_connector_integration_payouts!( connector::Cryptopay, connector::Coinbase, connector::Cybersource, - connector::Datatrans, connector::Deutschebank, connector::Digitalvirgo, connector::Dlocal, @@ -1129,7 +1100,6 @@ default_imp_for_new_connector_integration_payouts!( connector::Payone, connector::Paypal, connector::Payu, - connector::Placetopay, connector::Powertranz, connector::Rapyd, connector::Razorpay, @@ -1179,11 +1149,9 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1197,11 +1165,9 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1236,11 +1202,9 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1254,11 +1218,9 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1293,11 +1255,9 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1311,11 +1271,9 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1350,11 +1308,9 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1368,11 +1324,9 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1407,11 +1361,9 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1425,11 +1377,9 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1464,11 +1414,9 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1482,11 +1430,9 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1521,11 +1467,9 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1539,11 +1483,9 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1578,11 +1520,9 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1596,11 +1536,9 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1633,11 +1571,9 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1651,11 +1587,9 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1694,7 +1628,6 @@ default_imp_for_new_connector_integration_frm!( connector::Cryptopay, connector::Coinbase, connector::Cybersource, - connector::Datatrans, connector::Deutschebank, connector::Digitalvirgo, connector::Dlocal, @@ -1732,7 +1665,6 @@ default_imp_for_new_connector_integration_frm!( connector::Payone, connector::Paypal, connector::Payu, - connector::Placetopay, connector::Powertranz, connector::Rapyd, connector::Razorpay, @@ -1782,11 +1714,9 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1800,11 +1730,9 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1839,11 +1767,9 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1857,11 +1783,9 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1896,11 +1820,9 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1914,11 +1836,9 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -1953,11 +1873,9 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1971,11 +1889,9 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -2010,11 +1926,9 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2028,11 +1942,9 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, @@ -2064,11 +1976,9 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2082,11 +1992,9 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Stripe, diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 9ce0ccb4496a..ba1964435b80 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -213,7 +213,6 @@ default_imp_for_complete_authorize!( connector::Adyen, connector::Bankofamerica, connector::Checkout, - connector::Datatrans, connector::Ebanx, connector::Gpayments, connector::Iatapay, @@ -225,7 +224,6 @@ default_imp_for_complete_authorize!( connector::Opayo, connector::Opennode, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -268,11 +266,9 @@ default_imp_for_webhook_source_verification!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -286,10 +282,8 @@ default_imp_for_webhook_source_verification!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -334,11 +328,9 @@ default_imp_for_create_customer!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -352,11 +344,9 @@ default_imp_for_create_customer!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -402,7 +392,6 @@ default_imp_for_connector_redirect_response!( connector::Adyen, connector::Bankofamerica, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Gpayments, connector::Iatapay, @@ -413,7 +402,6 @@ default_imp_for_connector_redirect_response!( connector::Opayo, connector::Opennode, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -554,10 +542,8 @@ default_imp_for_accept_dispute!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -571,11 +557,9 @@ default_imp_for_accept_dispute!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -641,10 +625,8 @@ default_imp_for_file_upload!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -657,11 +639,9 @@ default_imp_for_file_upload!( connector::Noon, connector::Nuvei, connector::Opayo, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -705,10 +685,8 @@ default_imp_for_submit_evidence!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -721,11 +699,9 @@ default_imp_for_submit_evidence!( connector::Noon, connector::Nuvei, connector::Opayo, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -769,10 +745,8 @@ default_imp_for_defend_dispute!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -785,11 +759,9 @@ default_imp_for_defend_dispute!( connector::Noon, connector::Nuvei, connector::Opayo, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -849,10 +821,8 @@ default_imp_for_pre_processing_steps!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, - connector::Datatrans, connector::Ebanx, connector::Iatapay, connector::Itaubank, @@ -864,9 +834,7 @@ default_imp_for_pre_processing_steps!( connector::Noon, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -901,10 +869,8 @@ default_imp_for_post_processing_steps!( connector::Trustpay, connector::Aci, connector::Authorizedotnet, - connector::Bluesnap, connector::Braintree, connector::Checkout, - connector::Datatrans, connector::Ebanx, connector::Iatapay, connector::Itaubank, @@ -916,9 +882,7 @@ default_imp_for_post_processing_steps!( connector::Noon, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payone, - connector::Placetopay, connector::Riskified, connector::Signifyd, connector::Threedsecureio, @@ -942,10 +906,8 @@ default_imp_for_payouts!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -958,9 +920,7 @@ default_imp_for_payouts!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1003,11 +963,9 @@ default_imp_for_payouts_create!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -1020,10 +978,8 @@ default_imp_for_payouts_create!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1067,11 +1023,9 @@ default_imp_for_payouts_retrieve!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1085,10 +1039,8 @@ default_imp_for_payouts_retrieve!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1136,11 +1088,9 @@ default_imp_for_payouts_eligibility!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -1153,11 +1103,9 @@ default_imp_for_payouts_eligibility!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1200,10 +1148,8 @@ default_imp_for_payouts_fulfill!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -1216,9 +1162,7 @@ default_imp_for_payouts_fulfill!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1261,11 +1205,9 @@ default_imp_for_payouts_cancel!( connector::Aci, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -1278,11 +1220,9 @@ default_imp_for_payouts_cancel!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1326,11 +1266,9 @@ default_imp_for_payouts_quote!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -1343,11 +1281,9 @@ default_imp_for_payouts_quote!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1392,11 +1328,9 @@ default_imp_for_payouts_recipient!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -1409,11 +1343,9 @@ default_imp_for_payouts_recipient!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1460,11 +1392,9 @@ default_imp_for_payouts_recipient_account!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1478,11 +1408,9 @@ default_imp_for_payouts_recipient_account!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1526,11 +1454,9 @@ default_imp_for_approve!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1544,11 +1470,9 @@ default_imp_for_approve!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1593,11 +1517,9 @@ default_imp_for_reject!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1611,11 +1533,9 @@ default_imp_for_reject!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -1758,11 +1678,9 @@ default_imp_for_frm_sale!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1776,11 +1694,9 @@ default_imp_for_frm_sale!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Stripe, connector::Threedsecureio, @@ -1825,11 +1741,9 @@ default_imp_for_frm_checkout!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1843,11 +1757,9 @@ default_imp_for_frm_checkout!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Stripe, connector::Threedsecureio, @@ -1892,11 +1804,9 @@ default_imp_for_frm_transaction!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1910,11 +1820,9 @@ default_imp_for_frm_transaction!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Stripe, connector::Threedsecureio, @@ -1959,11 +1867,9 @@ default_imp_for_frm_fulfillment!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -1977,11 +1883,9 @@ default_imp_for_frm_fulfillment!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Stripe, connector::Threedsecureio, @@ -2026,11 +1930,9 @@ default_imp_for_frm_record_return!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2044,11 +1946,9 @@ default_imp_for_frm_record_return!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Stripe, connector::Threedsecureio, @@ -2091,10 +1991,8 @@ default_imp_for_incremental_authorization!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2108,11 +2006,9 @@ default_imp_for_incremental_authorization!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -2154,10 +2050,8 @@ default_imp_for_revoking_mandates!( connector::Adyen, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2170,11 +2064,9 @@ default_imp_for_revoking_mandates!( connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -2384,11 +2276,9 @@ default_imp_for_authorize_session_token!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2401,11 +2291,9 @@ default_imp_for_authorize_session_token!( connector::Noon, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -2448,11 +2336,9 @@ default_imp_for_calculate_tax!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2466,11 +2352,9 @@ default_imp_for_calculate_tax!( connector::Noon, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, connector::Paypal, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -2513,11 +2397,9 @@ default_imp_for_session_update!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2531,10 +2413,8 @@ default_imp_for_session_update!( connector::Noon, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, @@ -2577,11 +2457,9 @@ default_imp_for_post_session_tokens!( connector::Adyenplatform, connector::Authorizedotnet, connector::Bankofamerica, - connector::Bluesnap, connector::Braintree, connector::Checkout, connector::Cybersource, - connector::Datatrans, connector::Ebanx, connector::Globalpay, connector::Gpayments, @@ -2595,10 +2473,8 @@ default_imp_for_post_session_tokens!( connector::Noon, connector::Opayo, connector::Opennode, - connector::Paybox, connector::Payme, connector::Payone, - connector::Placetopay, connector::Plaid, connector::Riskified, connector::Signifyd, From fb3a49be658c3c4374ca98f9eae5d88dc92a3669 Mon Sep 17 00:00:00 2001 From: ShivanshMathurJuspay <104988143+ShivanshMathurJuspay@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:03:20 +0530 Subject: [PATCH 20/51] refactor(kafka_message): NanoSecond precision for consolidated logs (#6771) --- crates/router/src/services/kafka/dispute_event.rs | 10 +++++----- .../src/services/kafka/payment_attempt_event.rs | 8 ++++---- .../src/services/kafka/payment_intent_event.rs | 12 ++++++------ crates/router/src/services/kafka/refund_event.rs | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/router/src/services/kafka/dispute_event.rs b/crates/router/src/services/kafka/dispute_event.rs index 92327c044d74..45e7ff2c7981 100644 --- a/crates/router/src/services/kafka/dispute_event.rs +++ b/crates/router/src/services/kafka/dispute_event.rs @@ -20,15 +20,15 @@ pub struct KafkaDisputeEvent<'a> { pub connector_dispute_id: &'a String, pub connector_reason: Option<&'a String>, pub connector_reason_code: Option<&'a String>, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub challenge_required_by: Option, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub connector_created_at: Option, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub connector_updated_at: Option, - #[serde(default, with = "time::serde::timestamp::milliseconds")] + #[serde(default, with = "time::serde::timestamp::nanoseconds")] pub created_at: OffsetDateTime, - #[serde(default, with = "time::serde::timestamp::milliseconds")] + #[serde(default, with = "time::serde::timestamp::nanoseconds")] pub modified_at: OffsetDateTime, pub connector: &'a String, pub evidence: &'a Secret, diff --git a/crates/router/src/services/kafka/payment_attempt_event.rs b/crates/router/src/services/kafka/payment_attempt_event.rs index 177b211ae897..ec67dc759533 100644 --- a/crates/router/src/services/kafka/payment_attempt_event.rs +++ b/crates/router/src/services/kafka/payment_attempt_event.rs @@ -25,15 +25,15 @@ pub struct KafkaPaymentAttemptEvent<'a> { pub payment_method: Option, pub connector_transaction_id: Option<&'a String>, pub capture_method: Option, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub capture_on: Option, pub confirm: bool, pub authentication_type: Option, - #[serde(with = "time::serde::timestamp::milliseconds")] + #[serde(with = "time::serde::timestamp::nanoseconds")] pub created_at: OffsetDateTime, - #[serde(with = "time::serde::timestamp::milliseconds")] + #[serde(with = "time::serde::timestamp::nanoseconds")] pub modified_at: OffsetDateTime, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub last_synced: Option, pub cancellation_reason: Option<&'a String>, pub amount_to_capture: Option, diff --git a/crates/router/src/services/kafka/payment_intent_event.rs b/crates/router/src/services/kafka/payment_intent_event.rs index 7509f7116206..195b8679d318 100644 --- a/crates/router/src/services/kafka/payment_intent_event.rs +++ b/crates/router/src/services/kafka/payment_intent_event.rs @@ -22,11 +22,11 @@ pub struct KafkaPaymentIntentEvent<'a> { pub connector_id: Option<&'a String>, pub statement_descriptor_name: Option<&'a String>, pub statement_descriptor_suffix: Option<&'a String>, - #[serde(with = "time::serde::timestamp::milliseconds")] + #[serde(with = "time::serde::timestamp::nanoseconds")] pub created_at: OffsetDateTime, - #[serde(with = "time::serde::timestamp::milliseconds")] + #[serde(with = "time::serde::timestamp::nanoseconds")] pub modified_at: OffsetDateTime, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub last_synced: Option, pub setup_future_usage: Option, pub off_session: Option, @@ -60,11 +60,11 @@ pub struct KafkaPaymentIntentEvent<'a> { pub return_url: Option<&'a String>, pub metadata: Option, pub statement_descriptor: Option<&'a String>, - #[serde(with = "time::serde::timestamp::milliseconds")] + #[serde(with = "time::serde::timestamp::nanoseconds")] pub created_at: OffsetDateTime, - #[serde(with = "time::serde::timestamp::milliseconds")] + #[serde(with = "time::serde::timestamp::nanoseconds")] pub modified_at: OffsetDateTime, - #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + #[serde(default, with = "time::serde::timestamp::nanoseconds::option")] pub last_synced: Option, pub setup_future_usage: Option, pub off_session: Option, diff --git a/crates/router/src/services/kafka/refund_event.rs b/crates/router/src/services/kafka/refund_event.rs index 74278944b041..b9b3db17b588 100644 --- a/crates/router/src/services/kafka/refund_event.rs +++ b/crates/router/src/services/kafka/refund_event.rs @@ -24,9 +24,9 @@ pub struct KafkaRefundEvent<'a> { pub sent_to_gateway: &'a bool, pub refund_error_message: Option<&'a String>, pub refund_arn: Option<&'a String>, - #[serde(default, with = "time::serde::timestamp::milliseconds")] + #[serde(default, with = "time::serde::timestamp::nanoseconds")] pub created_at: OffsetDateTime, - #[serde(default, with = "time::serde::timestamp::milliseconds")] + #[serde(default, with = "time::serde::timestamp::nanoseconds")] pub modified_at: OffsetDateTime, pub description: Option<&'a String>, pub attempt_id: &'a String, From 573fc2ce0ff306d15ec97e7c8d5b8a03528165f4 Mon Sep 17 00:00:00 2001 From: Debarati Ghatak <88573135+cookieg13@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:04:37 +0530 Subject: [PATCH 21/51] feat(connector): [DEUTSCHEBANK, FIUU ] Handle 2xx errors given by Connector (#6727) --- .../connectors/deutschebank/transformers.rs | 264 ++++++++++++------ .../src/connectors/fiuu/transformers.rs | 50 +++- 2 files changed, 211 insertions(+), 103 deletions(-) diff --git a/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs b/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs index 328940d83aee..85c5fc8dc816 100644 --- a/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs @@ -5,7 +5,7 @@ use common_utils::{ext_traits::ValueExt, pii::Email, types::MinorUnit}; use error_stack::ResultExt; use hyperswitch_domain_models::{ payment_method_data::{BankDebitData, PaymentMethodData}, - router_data::{AccessToken, ConnectorAuthType, RouterData}, + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, router_flow_types::{ payments::{Authorize, Capture, CompleteAuthorize, PSync}, refunds::{Execute, RSync}, @@ -263,6 +263,21 @@ pub struct DeutschebankMandatePostResponse { state: Option, } +fn get_error_response(error_code: String, error_reason: String, status_code: u16) -> ErrorResponse { + ErrorResponse { + code: error_code.to_string(), + message: error_reason.clone(), + reason: Some(error_reason), + status_code, + attempt_status: None, + connector_transaction_id: None, + } +} + +fn is_response_success(rc: &String) -> bool { + rc == "0" +} + impl TryFrom< ResponseRouterData< @@ -286,16 +301,16 @@ impl Some(date) => date.chars().take(10).collect(), None => time::OffsetDateTime::now_utc().date().to_string(), }; - match item.response.reference.clone() { - Some(reference) => Ok(Self { - status: if item.response.rc == "0" { - match item.response.state.clone() { - Some(state) => common_enums::AttemptStatus::from(state), - None => common_enums::AttemptStatus::Failure, - } - } else { - common_enums::AttemptStatus::Failure - }, + let response_code = item.response.rc.clone(); + let is_response_success = is_response_success(&response_code); + + match ( + item.response.reference.clone(), + item.response.state.clone(), + is_response_success, + ) { + (Some(reference), Some(state), true) => Ok(Self { + status: common_enums::AttemptStatus::from(state), response: Ok(PaymentsResponseData::TransactionResponse { resource_id: ResponseId::NoResponseId, redirection_data: Box::new(Some(RedirectForm::Form { @@ -340,8 +355,13 @@ impl }), ..item.data }), - None => Ok(Self { + _ => Ok(Self { status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), ..item.data }), } @@ -367,27 +387,36 @@ impl PaymentsResponseData, >, ) -> Result { - Ok(Self { - status: if item.response.rc == "0" { - match item.data.request.is_auto_capture()? { + let response_code = item.response.rc.clone(); + if is_response_success(&response_code) { + Ok(Self { + status: match item.data.request.is_auto_capture()? { true => common_enums::AttemptStatus::Charged, false => common_enums::AttemptStatus::Authorized, - } - } else { - common_enums::AttemptStatus::Failure - }, - response: Ok(PaymentsResponseData::TransactionResponse { - resource_id: ResponseId::ConnectorTransactionId(item.response.tx_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, - }), - ..item.data - }) + }, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.tx_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, + }), + ..item.data + }) + } else { + Ok(Self { + status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }) + } } } @@ -570,27 +599,36 @@ impl PaymentsResponseData, >, ) -> Result { - Ok(Self { - status: if item.response.rc == "0" { - match item.data.request.is_auto_capture()? { + let response_code = item.response.rc.clone(); + if is_response_success(&response_code) { + Ok(Self { + status: match item.data.request.is_auto_capture()? { true => common_enums::AttemptStatus::Charged, false => common_enums::AttemptStatus::Authorized, - } - } else { - common_enums::AttemptStatus::Failure - }, - response: Ok(PaymentsResponseData::TransactionResponse { - resource_id: ResponseId::ConnectorTransactionId(item.response.tx_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, - }), - ..item.data - }) + }, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.tx_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, + }), + ..item.data + }) + } else { + Ok(Self { + status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }) + } } } @@ -637,24 +675,33 @@ impl PaymentsResponseData, >, ) -> Result { - Ok(Self { - response: Ok(PaymentsResponseData::TransactionResponse { - resource_id: ResponseId::ConnectorTransactionId(item.response.tx_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, - }), - status: if item.response.rc == "0" { - common_enums::AttemptStatus::Charged - } else { - common_enums::AttemptStatus::Failure - }, - ..item.data - }) + let response_code = item.response.rc.clone(); + if is_response_success(&response_code) { + Ok(Self { + status: common_enums::AttemptStatus::Charged, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.tx_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, + }), + ..item.data + }) + } else { + Ok(Self { + status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }) + } } } @@ -677,7 +724,8 @@ impl PaymentsResponseData, >, ) -> Result { - let status = if item.response.rc == "0" { + let response_code = item.response.rc.clone(); + let status = if is_response_success(&response_code) { item.response .tx_action .and_then(|tx_action| match tx_action { @@ -699,6 +747,15 @@ impl Some(common_enums::AttemptStatus::Failure) }; match status { + Some(common_enums::AttemptStatus::Failure) => Ok(Self { + status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }), Some(status) => Ok(Self { status, ..item.data @@ -729,14 +786,23 @@ impl TryFrom> fn try_from( item: PaymentsCancelResponseRouterData, ) -> Result { - Ok(Self { - status: if item.response.rc == "0" { - common_enums::AttemptStatus::Voided - } else { - common_enums::AttemptStatus::VoidFailed - }, - ..item.data - }) + let response_code = item.response.rc.clone(); + if is_response_success(&response_code) { + Ok(Self { + status: common_enums::AttemptStatus::Voided, + ..item.data + }) + } else { + Ok(Self { + status: common_enums::AttemptStatus::VoidFailed, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }) + } } } @@ -763,17 +829,26 @@ impl TryFrom> fn try_from( item: RefundsResponseRouterData, ) -> Result { - Ok(Self { - response: Ok(RefundsResponseData { - connector_refund_id: item.response.tx_id, - refund_status: if item.response.rc == "0" { - enums::RefundStatus::Success - } else { - enums::RefundStatus::Failure - }, - }), - ..item.data - }) + let response_code = item.response.rc.clone(); + if is_response_success(&response_code) { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: item.response.tx_id, + refund_status: enums::RefundStatus::Success, + }), + ..item.data + }) + } else { + Ok(Self { + status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }) + } } } @@ -784,7 +859,8 @@ impl TryFrom> fn try_from( item: RefundsResponseRouterData, ) -> Result { - let status = if item.response.rc == "0" { + let response_code = item.response.rc.clone(); + let status = if is_response_success(&response_code) { item.response .tx_action .and_then(|tx_action| match tx_action { @@ -803,7 +879,17 @@ impl TryFrom> } else { Some(enums::RefundStatus::Failure) }; + match status { + Some(enums::RefundStatus::Failure) => Ok(Self { + status: common_enums::AttemptStatus::Failure, + response: Err(get_error_response( + response_code.clone(), + item.response.message.clone(), + item.http_code, + )), + ..item.data + }), Some(refund_status) => Ok(Self { response: Ok(RefundsResponseData { refund_status, diff --git a/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs b/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs index f8f57887c280..143cd1aa0474 100644 --- a/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs @@ -993,6 +993,8 @@ pub struct FiuuRefundSuccessResponse { #[serde(rename = "RefundID")] refund_id: i64, status: String, + #[serde(rename = "reason")] + reason: Option, } #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] @@ -1019,20 +1021,40 @@ impl TryFrom> }), ..item.data }), - FiuuRefundResponse::Success(refund_data) => Ok(Self { - response: Ok(RefundsResponseData { - connector_refund_id: refund_data.refund_id.to_string(), - refund_status: match refund_data.status.as_str() { - "00" => Ok(enums::RefundStatus::Success), - "11" => Ok(enums::RefundStatus::Failure), - "22" => Ok(enums::RefundStatus::Pending), - other => Err(errors::ConnectorError::UnexpectedResponseError( - bytes::Bytes::from(other.to_owned()), - )), - }?, - }), - ..item.data - }), + FiuuRefundResponse::Success(refund_data) => { + let refund_status = match refund_data.status.as_str() { + "00" => Ok(enums::RefundStatus::Success), + "11" => Ok(enums::RefundStatus::Failure), + "22" => Ok(enums::RefundStatus::Pending), + other => Err(errors::ConnectorError::UnexpectedResponseError( + bytes::Bytes::from(other.to_owned()), + )), + }?; + if refund_status == enums::RefundStatus::Failure { + Ok(Self { + response: Err(ErrorResponse { + code: refund_data.status.clone(), + message: refund_data + .reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: refund_data.reason.clone(), + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: None, + }), + ..item.data + }) + } else { + Ok(Self { + response: Ok(RefundsResponseData { + connector_refund_id: refund_data.refund_id.to_string(), + refund_status, + }), + ..item.data + }) + } + } } } } From e9a5615f2ba1f6cc27bbef653c42326b50da8db7 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 12 Dec 2024 17:31:41 +0530 Subject: [PATCH 22/51] feat(core): Add service details field in authentication table (#6757) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- api-reference-v2/openapi_spec.json | 25 ++++++++ api-reference/openapi_spec.json | 57 +++++++++++++++++++ crates/api_models/src/payments.rs | 16 ++++++ crates/diesel_models/src/authentication.rs | 6 ++ crates/diesel_models/src/schema.rs | 1 + crates/diesel_models/src/schema_v2.rs | 1 + .../unified_authentication_service.rs | 4 +- crates/openapi/src/openapi.rs | 1 + crates/openapi/src/openapi_v2.rs | 1 + .../router/src/core/authentication/utils.rs | 1 + crates/router/src/core/payments.rs | 1 + .../payments/operations/payment_approve.rs | 1 + .../payments/operations/payment_cancel.rs | 1 + .../payments/operations/payment_capture.rs | 1 + .../operations/payment_complete_authorize.rs | 1 + .../payments/operations/payment_confirm.rs | 1 + .../payments/operations/payment_create.rs | 1 + .../operations/payment_post_session_tokens.rs | 1 + .../payments/operations/payment_reject.rs | 1 + .../payments/operations/payment_session.rs | 1 + .../core/payments/operations/payment_start.rs | 1 + .../payments/operations/payment_status.rs | 1 + .../payments/operations/payment_update.rs | 1 + .../payments_incremental_authorization.rs | 1 + .../payments/operations/tax_calculation.rs | 1 + .../core/unified_authentication_service.rs | 1 + .../transformers.rs | 4 +- crates/router/src/db/authentication.rs | 1 + .../down.sql | 2 + .../up.sql | 4 ++ 30 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 migrations/2024-12-05-115544_add-service-details/down.sql create mode 100644 migrations/2024-12-05-115544_add-service-details/up.sql diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 2cd5467f06eb..2ea0f42a7f49 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -6942,6 +6942,31 @@ } ] }, + "CtpServiceDetails": { + "type": "object", + "properties": { + "merchant_transaction_id": { + "type": "string", + "description": "merchant transaction id", + "nullable": true + }, + "correlation_id": { + "type": "string", + "description": "network transaction correlation id", + "nullable": true + }, + "x_src_flow_id": { + "type": "string", + "description": "session transaction flow id", + "nullable": true + }, + "provider": { + "type": "string", + "description": "provider Eg: Visa, Mastercard", + "nullable": true + } + } + }, "Currency": { "type": "string", "description": "The three letter ISO currency code in uppercase. Eg: 'USD' for the United States Dollar.", diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 937dc7ab2d9a..832f8da9c419 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -9304,6 +9304,31 @@ } ] }, + "CtpServiceDetails": { + "type": "object", + "properties": { + "merchant_transaction_id": { + "type": "string", + "description": "merchant transaction id", + "nullable": true + }, + "correlation_id": { + "type": "string", + "description": "network transaction correlation id", + "nullable": true + }, + "x_src_flow_id": { + "type": "string", + "description": "session transaction flow id", + "nullable": true + }, + "provider": { + "type": "string", + "description": "provider Eg: Visa, Mastercard", + "nullable": true + } + } + }, "Currency": { "type": "string", "description": "The three letter ISO currency code in uppercase. Eg: 'USD' for the United States Dollar.", @@ -17109,6 +17134,14 @@ } ], "nullable": true + }, + "ctp_service_details": { + "allOf": [ + { + "$ref": "#/components/schemas/CtpServiceDetails" + } + ], + "nullable": true } } }, @@ -17487,6 +17520,14 @@ } ], "nullable": true + }, + "ctp_service_details": { + "allOf": [ + { + "$ref": "#/components/schemas/CtpServiceDetails" + } + ], + "nullable": true } } }, @@ -18689,6 +18730,14 @@ } ], "nullable": true + }, + "ctp_service_details": { + "allOf": [ + { + "$ref": "#/components/schemas/CtpServiceDetails" + } + ], + "nullable": true } }, "additionalProperties": false @@ -19730,6 +19779,14 @@ } ], "nullable": true + }, + "ctp_service_details": { + "allOf": [ + { + "$ref": "#/components/schemas/CtpServiceDetails" + } + ], + "nullable": true } } }, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index cab8071de087..2114bc9f6ca5 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1013,6 +1013,22 @@ pub struct PaymentsRequest { /// Choose what kind of sca exemption is required for this payment #[schema(value_type = Option)] pub psd2_sca_exemption_type: Option, + + /// Service details for click to pay external authentication + #[schema(value_type = Option)] + pub ctp_service_details: Option, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct CtpServiceDetails { + /// merchant transaction id + pub merchant_transaction_id: Option, + /// network transaction correlation id + pub correlation_id: Option, + /// session transaction flow id + pub x_src_flow_id: Option, + /// provider Eg: Visa, Mastercard + pub provider: Option, } #[cfg(feature = "v1")] diff --git a/crates/diesel_models/src/authentication.rs b/crates/diesel_models/src/authentication.rs index 5d0e58c56270..c79892d27bf6 100644 --- a/crates/diesel_models/src/authentication.rs +++ b/crates/diesel_models/src/authentication.rs @@ -47,6 +47,7 @@ pub struct Authentication { pub ds_trans_id: Option, pub directory_server_id: Option, pub acquirer_country_code: Option, + pub service_details: Option, } impl Authentication { @@ -94,6 +95,7 @@ pub struct AuthenticationNew { pub ds_trans_id: Option, pub directory_server_id: Option, pub acquirer_country_code: Option, + pub service_details: Option, } #[derive(Debug)] @@ -190,6 +192,7 @@ pub struct AuthenticationUpdateInternal { pub ds_trans_id: Option, pub directory_server_id: Option, pub acquirer_country_code: Option, + pub service_details: Option, } impl Default for AuthenticationUpdateInternal { @@ -223,6 +226,7 @@ impl Default for AuthenticationUpdateInternal { ds_trans_id: Default::default(), directory_server_id: Default::default(), acquirer_country_code: Default::default(), + service_details: Default::default(), } } } @@ -258,6 +262,7 @@ impl AuthenticationUpdateInternal { ds_trans_id, directory_server_id, acquirer_country_code, + service_details, } = self; Authentication { connector_authentication_id: connector_authentication_id @@ -292,6 +297,7 @@ impl AuthenticationUpdateInternal { ds_trans_id: ds_trans_id.or(source.ds_trans_id), directory_server_id: directory_server_id.or(source.directory_server_id), acquirer_country_code: acquirer_country_code.or(source.acquirer_country_code), + service_details: service_details.or(source.service_details), ..source } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index c30562de9913..82f1ffed1df3 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -120,6 +120,7 @@ diesel::table! { directory_server_id -> Nullable, #[max_length = 64] acquirer_country_code -> Nullable, + service_details -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 12bb19c0a7f1..6c91e258de7b 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -121,6 +121,7 @@ diesel::table! { directory_server_id -> Nullable, #[max_length = 64] acquirer_country_code -> Nullable, + service_details -> Nullable, } } 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 cbca353b1009..6dd899cd5b38 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 @@ -2,12 +2,12 @@ use masking::Secret; #[derive(Clone, serde::Deserialize, Debug, serde::Serialize)] pub struct UasPreAuthenticationRequestData { - pub service_details: Option, + pub service_details: Option, pub transaction_details: Option, } #[derive(Clone, serde::Deserialize, Debug, serde::Serialize)] -pub struct ServiceDetails { +pub struct CtpServiceDetails { pub service_session_ids: Option, } diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index c7fa29a1b20e..d50bf863b5b8 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -655,6 +655,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::DisplayAmountOnSdk, api_models::payments::PaymentsPostSessionTokensRequest, api_models::payments::PaymentsPostSessionTokensResponse, + api_models::payments::CtpServiceDetails )), modifiers(&SecurityAddon) )] diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index ba2975349c0f..688d749d5d99 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -621,6 +621,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsDynamicTaxCalculationResponse, api_models::payments::DisplayAmountOnSdk, api_models::payments::ErrorDetails, + api_models::payments::CtpServiceDetails, common_utils::types::BrowserInformation, api_models::payments::ConfirmIntentAmountDetailsResponse, routes::payments::ForceSync, diff --git a/crates/router/src/core/authentication/utils.rs b/crates/router/src/core/authentication/utils.rs index 01cc6a89562d..21c2ae20e2ca 100644 --- a/crates/router/src/core/authentication/utils.rs +++ b/crates/router/src/core/authentication/utils.rs @@ -219,6 +219,7 @@ pub async fn create_new_authentication( ds_trans_id: None, directory_server_id: None, acquirer_country_code: None, + service_details: None, }; state .store diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 7912eb090d51..3299bdccac5d 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -4262,6 +4262,7 @@ where pub poll_config: Option, pub tax_data: Option, pub session_id: Option, + pub service_details: Option, } #[derive(Clone, serde::Serialize, Debug)] diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index b3d2985bf803..a5993eb2f012 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -194,6 +194,7 @@ impl GetTracker, api::PaymentsCaptureR poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index a40ecf0242e7..427c10aab629 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -205,6 +205,7 @@ impl GetTracker, api::PaymentsCancelRe poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index d9068b402ce8..f8d304bcb79c 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -254,6 +254,7 @@ impl GetTracker, api::Paymen poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { 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 f4f5813c1b04..09e806755ff0 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -348,6 +348,7 @@ impl GetTracker, api::PaymentsRequest> poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let customer_details = Some(CustomerDetails { diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index c3fe518ff5eb..58217ef3f41a 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -818,6 +818,7 @@ impl GetTracker, api::PaymentsRequest> poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 6b9a4a76711e..9dd3cdaaa71c 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -613,6 +613,7 @@ impl GetTracker, api::PaymentsRequest> poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs index 7c30d9c5b759..7337f0808847 100644 --- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs +++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs @@ -165,6 +165,7 @@ impl GetTracker, api::PaymentsPostSess poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index df9544dfb486..a6a10be8e9ab 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -192,6 +192,7 @@ impl GetTracker, PaymentsCancelRequest poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index a9a64c688094..f93327b275cf 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -212,6 +212,7 @@ impl GetTracker, api::PaymentsSessionR poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 3285914affae..a895855cefc8 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -199,6 +199,7 @@ impl GetTracker, api::PaymentsStartReq poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index e2c9a4d7a3ba..69f2d85d6a91 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -508,6 +508,7 @@ async fn get_tracker_for_sync< poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 1fba79968b68..ed8b6391da63 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -490,6 +490,7 @@ impl GetTracker, api::PaymentsRequest> poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index a629938936b6..035c4e8e2ecf 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -171,6 +171,7 @@ impl poll_config: None, tax_data: None, session_id: None, + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs index dbfed35a44fa..859422920e16 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -179,6 +179,7 @@ impl poll_config: None, tax_data: Some(tax_data), session_id: request.session_id.clone(), + service_details: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/unified_authentication_service.rs b/crates/router/src/core/unified_authentication_service.rs index bd08ea7fe6b7..63375419cf75 100644 --- a/crates/router/src/core/unified_authentication_service.rs +++ b/crates/router/src/core/unified_authentication_service.rs @@ -173,6 +173,7 @@ pub async fn create_new_authentication( ds_trans_id: None, directory_server_id: None, acquirer_country_code: None, + service_details: None, }; 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 cf3cb6f1f631..0dd59fc81c76 100644 --- a/crates/router/src/core/unified_authentication_service/transformers.rs +++ b/crates/router/src/core/unified_authentication_service/transformers.rs @@ -2,7 +2,7 @@ use error_stack::Report; use hyperswitch_domain_models::{ errors::api_error_response::ApiErrorResponse, router_request_types::unified_authentication_service::{ - ServiceDetails, ServiceSessionIds, TransactionDetails, UasPreAuthenticationRequestData, + CtpServiceDetails, ServiceSessionIds, TransactionDetails, UasPreAuthenticationRequestData, }, }; @@ -12,7 +12,7 @@ use crate::core::payments::PaymentData; impl TryFrom> for UasPreAuthenticationRequestData { type Error = Report; fn try_from(payment_data: PaymentData) -> Result { - let service_details = ServiceDetails { + let service_details = CtpServiceDetails { service_session_ids: Some(ServiceSessionIds { merchant_transaction_id: None, correlation_id: None, diff --git a/crates/router/src/db/authentication.rs b/crates/router/src/db/authentication.rs index 1307c53338de..af3da68e6ae5 100644 --- a/crates/router/src/db/authentication.rs +++ b/crates/router/src/db/authentication.rs @@ -150,6 +150,7 @@ impl AuthenticationInterface for MockDb { ds_trans_id: authentication.ds_trans_id, directory_server_id: authentication.directory_server_id, acquirer_country_code: authentication.acquirer_country_code, + service_details: authentication.service_details, }; authentications.push(authentication.clone()); Ok(authentication) diff --git a/migrations/2024-12-05-115544_add-service-details/down.sql b/migrations/2024-12-05-115544_add-service-details/down.sql new file mode 100644 index 000000000000..1c42146adfc1 --- /dev/null +++ b/migrations/2024-12-05-115544_add-service-details/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE authentication DROP COLUMN IF EXISTS service_details; \ No newline at end of file diff --git a/migrations/2024-12-05-115544_add-service-details/up.sql b/migrations/2024-12-05-115544_add-service-details/up.sql new file mode 100644 index 000000000000..3555647a987e --- /dev/null +++ b/migrations/2024-12-05-115544_add-service-details/up.sql @@ -0,0 +1,4 @@ +-- Your SQL goes here +ALTER TABLE authentication +ADD COLUMN IF NOT EXISTS service_details JSONB +DEFAULT NULL; \ No newline at end of file From 1564ad72b80b184808584f97309620a18246d80c Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 12 Dec 2024 20:05:20 +0530 Subject: [PATCH 23/51] feat(core): Add product authentication ids in business profile (#6811) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- api-reference-v2/openapi_spec.json | 10 ++++++ api-reference/openapi_spec.json | 10 ++++++ crates/api_models/src/admin.rs | 24 ++++++++++++++ crates/diesel_models/src/business_profile.rs | 12 +++++++ crates/diesel_models/src/schema.rs | 1 + crates/diesel_models/src/schema_v2.rs | 1 + .../src/business_profile.rs | 31 +++++++++++++++++- crates/router/src/core/admin.rs | 32 +++++++++++++++++++ crates/router/src/types/api/admin.rs | 10 ++++++ .../down.sql | 3 ++ .../up.sql | 3 ++ 11 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/down.sql create mode 100644 migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/up.sql diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 2ea0f42a7f49..6c3e9f5072ae 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -17762,6 +17762,11 @@ "description": "Indicates if click to pay is enabled or not.", "default": false, "example": false + }, + "authentication_product_ids": { + "type": "object", + "description": "Product authentication ids", + "nullable": true } }, "additionalProperties": false @@ -17981,6 +17986,11 @@ "description": "Indicates if click to pay is enabled or not.", "default": false, "example": false + }, + "authentication_product_ids": { + "type": "object", + "description": "Product authentication ids", + "nullable": true } } }, diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 832f8da9c419..ce383f240647 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -21748,6 +21748,11 @@ "is_click_to_pay_enabled": { "type": "boolean", "description": "Indicates if click to pay is enabled or not." + }, + "authentication_product_ids": { + "type": "object", + "description": "Product authentication ids", + "nullable": true } }, "additionalProperties": false @@ -21984,6 +21989,11 @@ "description": "Indicates if click to pay is enabled or not.", "default": false, "example": false + }, + "authentication_product_ids": { + "type": "object", + "description": "Product authentication ids", + "nullable": true } } }, diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 53ce86789665..769ef5928030 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -1970,6 +1970,10 @@ pub struct ProfileCreate { /// Indicates if click to pay is enabled or not. #[serde(default)] pub is_click_to_pay_enabled: bool, + + /// Product authentication ids + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub authentication_product_ids: Option>, } #[nutype::nutype( @@ -2082,6 +2086,10 @@ pub struct ProfileCreate { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: bool, + + /// Product authentication ids + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub authentication_product_ids: Option>, } #[cfg(feature = "v1")] @@ -2214,6 +2222,10 @@ pub struct ProfileResponse { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: bool, + + /// Product authentication ids + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub authentication_product_ids: Option, } #[cfg(feature = "v2")] @@ -2333,6 +2345,10 @@ pub struct ProfileResponse { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: bool, + + /// Product authentication ids + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -2459,6 +2475,10 @@ pub struct ProfileUpdate { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: Option, + + /// Product authentication ids + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub authentication_product_ids: Option>, } #[cfg(feature = "v2")] @@ -2566,6 +2586,10 @@ pub struct ProfileUpdate { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: Option, + + /// Product authentication ids + #[schema(value_type = Option, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)] + pub authentication_product_ids: Option>, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 484a1c0c699e..0cae67873d65 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -58,6 +58,7 @@ pub struct Profile { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -102,6 +103,7 @@ pub struct ProfileNew { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -143,6 +145,7 @@ pub struct ProfileUpdateInternal { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: Option, + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -183,6 +186,7 @@ impl ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + authentication_product_ids, } = self; Profile { profile_id: source.profile_id, @@ -244,6 +248,8 @@ impl ProfileUpdateInternal { max_auto_retries_enabled: max_auto_retries_enabled.or(source.max_auto_retries_enabled), is_click_to_pay_enabled: is_click_to_pay_enabled .unwrap_or(source.is_click_to_pay_enabled), + authentication_product_ids: authentication_product_ids + .or(source.authentication_product_ids), } } } @@ -299,6 +305,7 @@ pub struct Profile { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } impl Profile { @@ -358,6 +365,7 @@ pub struct ProfileNew { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v2")] @@ -401,6 +409,7 @@ pub struct ProfileUpdateInternal { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: Option, + pub authentication_product_ids: Option, } #[cfg(feature = "v2")] @@ -443,6 +452,7 @@ impl ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + authentication_product_ids, } = self; Profile { id: source.id, @@ -509,6 +519,8 @@ impl ProfileUpdateInternal { max_auto_retries_enabled: max_auto_retries_enabled.or(source.max_auto_retries_enabled), is_click_to_pay_enabled: is_click_to_pay_enabled .unwrap_or(source.is_click_to_pay_enabled), + authentication_product_ids: authentication_product_ids + .or(source.authentication_product_ids), } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 82f1ffed1df3..bb2aea070148 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -215,6 +215,7 @@ diesel::table! { is_auto_retries_enabled -> Nullable, max_auto_retries_enabled -> Nullable, is_click_to_pay_enabled -> Bool, + authentication_product_ids -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 6c91e258de7b..9960b136e701 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -223,6 +223,7 @@ diesel::table! { is_auto_retries_enabled -> Nullable, max_auto_retries_enabled -> Nullable, is_click_to_pay_enabled -> Bool, + authentication_product_ids -> Nullable, } } diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 433353b2f813..1df474f18d5f 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -59,6 +59,7 @@ pub struct Profile { pub is_auto_retries_enabled: bool, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -100,6 +101,7 @@ pub struct ProfileSetter { pub is_auto_retries_enabled: bool, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -148,6 +150,7 @@ impl From for Profile { is_auto_retries_enabled: value.is_auto_retries_enabled, max_auto_retries_enabled: value.max_auto_retries_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, + authentication_product_ids: value.authentication_product_ids, } } } @@ -198,6 +201,7 @@ pub struct ProfileGeneralUpdate { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: Option, + pub authentication_product_ids: Option, } #[cfg(feature = "v1")] @@ -261,6 +265,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + authentication_product_ids, } = *update; Self { @@ -299,6 +304,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + authentication_product_ids, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -339,6 +345,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::DynamicRoutingAlgorithmUpdate { dynamic_routing_algorithm, @@ -377,6 +384,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -415,6 +423,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -453,6 +462,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -491,6 +501,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, } } @@ -548,6 +559,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: Some(self.is_auto_retries_enabled), max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids: self.authentication_product_ids, }) } @@ -617,6 +629,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: item.is_auto_retries_enabled.unwrap_or(false), max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, + authentication_product_ids: item.authentication_product_ids, }) } .await @@ -670,6 +683,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: Some(self.is_auto_retries_enabled), max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids: self.authentication_product_ids, }) } } @@ -715,6 +729,7 @@ pub struct Profile { pub version: common_enums::ApiVersion, pub is_network_tokenization_enabled: bool, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v2")] @@ -756,6 +771,7 @@ pub struct ProfileSetter { pub is_tax_connector_enabled: bool, pub is_network_tokenization_enabled: bool, pub is_click_to_pay_enabled: bool, + pub authentication_product_ids: Option, } #[cfg(feature = "v2")] @@ -804,6 +820,7 @@ impl From for Profile { version: consts::API_VERSION, is_network_tokenization_enabled: value.is_network_tokenization_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, + authentication_product_ids: value.authentication_product_ids, } } } @@ -855,6 +872,7 @@ pub struct ProfileGeneralUpdate { pub order_fulfillment_time_origin: Option, pub is_network_tokenization_enabled: Option, pub is_click_to_pay_enabled: Option, + pub authentication_product_ids: Option, } #[cfg(feature = "v2")] @@ -914,6 +932,7 @@ impl From for ProfileUpdateInternal { order_fulfillment_time_origin, is_network_tokenization_enabled, is_click_to_pay_enabled, + authentication_product_ids, } = *update; Self { profile_name, @@ -952,7 +971,8 @@ impl From for ProfileUpdateInternal { is_network_tokenization_enabled, is_auto_retries_enabled: None, max_auto_retries_enabled: None, - is_click_to_pay_enabled, + is_click_to_pay_enabled: None, + authentication_product_ids, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -995,6 +1015,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -1035,6 +1056,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -1075,6 +1097,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::DefaultRoutingFallbackUpdate { default_fallback_routing, @@ -1115,6 +1138,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -1155,6 +1179,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, ProfileUpdate::CollectCvvDuringPaymentUpdate { should_collect_cvv_during_payment, @@ -1195,6 +1220,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + authentication_product_ids: None, }, } } @@ -1255,6 +1281,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids: self.authentication_product_ids, }) } @@ -1324,6 +1351,7 @@ impl super::behaviour::Conversion for Profile { version: item.version, is_network_tokenization_enabled: item.is_network_tokenization_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, + authentication_product_ids: item.authentication_product_ids, }) } .await @@ -1380,6 +1408,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids: self.authentication_product_ids, }) } } diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 8e2145071146..6cca6e9001e9 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3622,6 +3622,13 @@ impl ProfileCreateBridge for api::ProfileCreate { }) .transpose()?; + let authentication_product_ids = self + .authentication_product_ids + .map(serde_json::to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse product authentication id's to value")?; + Ok(domain::Profile::from(domain::ProfileSetter { profile_id, merchant_id: merchant_account.get_id().clone(), @@ -3692,6 +3699,7 @@ impl ProfileCreateBridge for api::ProfileCreate { is_auto_retries_enabled: self.is_auto_retries_enabled.unwrap_or_default(), max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids, })) } @@ -3743,6 +3751,13 @@ impl ProfileCreateBridge for api::ProfileCreate { }) .transpose()?; + let authentication_product_ids = self + .authentication_product_ids + .map(serde_json::to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse product authentication id's to value")?; + Ok(domain::Profile::from(domain::ProfileSetter { id: profile_id, merchant_id: merchant_id.clone(), @@ -3800,6 +3815,7 @@ impl ProfileCreateBridge for api::ProfileCreate { is_tax_connector_enabled: self.is_tax_connector_enabled, is_network_tokenization_enabled: self.is_network_tokenization_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids, })) } } @@ -4007,6 +4023,13 @@ impl ProfileUpdateBridge for api::ProfileUpdate { }) .transpose()?; + let authentication_product_ids = self + .authentication_product_ids + .map(serde_json::to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse product authentication id's to value")?; + Ok(domain::ProfileUpdate::Update(Box::new( domain::ProfileGeneralUpdate { profile_name: self.profile_name, @@ -4050,6 +4073,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate { is_auto_retries_enabled: self.is_auto_retries_enabled, max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids, }, ))) } @@ -4112,6 +4136,13 @@ impl ProfileUpdateBridge for api::ProfileUpdate { }) .transpose()?; + let authentication_product_ids = self + .authentication_product_ids + .map(serde_json::to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse product authentication id's to value")?; + Ok(domain::ProfileUpdate::Update(Box::new( domain::ProfileGeneralUpdate { profile_name: self.profile_name, @@ -4147,6 +4178,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate { .always_collect_shipping_details_from_wallet_connector, is_network_tokenization_enabled: self.is_network_tokenization_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + authentication_product_ids, }, ))) } diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 7207f63aa0fc..40d90125ba13 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -175,6 +175,7 @@ impl ForeignTryFrom for ProfileResponse { is_auto_retries_enabled: item.is_auto_retries_enabled, max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, + authentication_product_ids: item.authentication_product_ids, }) } } @@ -243,6 +244,7 @@ impl ForeignTryFrom for ProfileResponse { is_tax_connector_enabled: item.is_tax_connector_enabled, is_network_tokenization_enabled: item.is_network_tokenization_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, + authentication_product_ids: item.authentication_product_ids, }) } } @@ -299,6 +301,13 @@ pub async fn create_profile_from_merchant_account( }) .transpose()?; + let authentication_product_ids = request + .authentication_product_ids + .map(serde_json::to_value) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse product authentication id's to value")?; + Ok(domain::Profile::from(domain::ProfileSetter { profile_id, merchant_id, @@ -370,5 +379,6 @@ pub async fn create_profile_from_merchant_account( is_auto_retries_enabled: request.is_auto_retries_enabled.unwrap_or_default(), max_auto_retries_enabled: request.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: request.is_click_to_pay_enabled, + authentication_product_ids, })) } diff --git a/migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/down.sql b/migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/down.sql new file mode 100644 index 000000000000..a353beb4e403 --- /dev/null +++ b/migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE business_profile +DROP COLUMN IF EXISTS authentication_product_ids diff --git a/migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/up.sql b/migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/up.sql new file mode 100644 index 000000000000..4e94da05c0e2 --- /dev/null +++ b/migrations/2024-12-11-092649_add-authentication-product-ids-in-business-profile/up.sql @@ -0,0 +1,3 @@ +-- Your SQL goes here +ALTER TABLE business_profile +ADD COLUMN IF NOT EXISTS authentication_product_ids JSONB NULL; From d11d87408d0c4195bbe2c4c51df50f24c1d332c6 Mon Sep 17 00:00:00 2001 From: Kashif Date: Thu, 12 Dec 2024 20:50:33 +0530 Subject: [PATCH 24/51] feat(core): payment links - add support for custom background image and layout in details section (#6725) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- api-reference-v2/openapi_spec.json | 140 +++++++++++++++ api-reference/openapi_spec.json | 140 +++++++++++++++ config/deployments/production.toml | 2 +- crates/api_models/src/admin.rs | 27 +++ crates/api_models/src/payments.rs | 3 + crates/common_enums/src/enums.rs | 2 + crates/common_enums/src/enums/ui.rs | 149 +++++++++++++++ crates/diesel_models/src/business_profile.rs | 10 ++ crates/diesel_models/src/payment_intent.rs | 6 +- crates/hyperswitch_domain_models/src/lib.rs | 36 ++++ crates/openapi/src/openapi.rs | 5 + crates/openapi/src/openapi_v2.rs | 5 + crates/router/src/core/payment_link.rs | 78 +++++--- .../payment_link_initiate/payment_link.css | 15 +- .../payment_link_initiate/payment_link.html | 25 +-- .../payment_link_initiate/payment_link.js | 170 ++++++++++++++---- .../payment_link_initiator.js | 1 + .../router/src/core/payments/transformers.rs | 12 ++ crates/router/src/types/transformers.rs | 36 ++++ 19 files changed, 775 insertions(+), 87 deletions(-) create mode 100644 crates/common_enums/src/enums/ui.rs diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 6c3e9f5072ae..0f62f1112770 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -5537,6 +5537,11 @@ "description": "A list of allowed domains (glob patterns) where this link can be embedded / opened from", "uniqueItems": true, "nullable": true + }, + "branding_visibility": { + "type": "boolean", + "description": "Toggle for HyperSwitch branding visibility", + "nullable": true } } } @@ -7882,6 +7887,61 @@ } } }, + "ElementPosition": { + "type": "string", + "enum": [ + "left", + "top left", + "top", + "top right", + "right", + "bottom right", + "bottom", + "bottom left", + "center" + ] + }, + "ElementSize": { + "oneOf": [ + { + "type": "object", + "required": [ + "Variants" + ], + "properties": { + "Variants": { + "$ref": "#/components/schemas/SizeVariants" + } + } + }, + { + "type": "object", + "required": [ + "Percentage" + ], + "properties": { + "Percentage": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + }, + { + "type": "object", + "required": [ + "Pixels" + ], + "properties": { + "Pixels": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + } + ] + }, "EnablePaymentLinkRequest": { "type": "string", "description": "Whether payment link is requested to be enabled or not for this transaction", @@ -12540,6 +12600,35 @@ } } }, + "PaymentLinkBackgroundImageConfig": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL of the image", + "example": "https://hyperswitch.io/favicon.ico" + }, + "position": { + "allOf": [ + { + "$ref": "#/components/schemas/ElementPosition" + } + ], + "nullable": true + }, + "size": { + "allOf": [ + { + "$ref": "#/components/schemas/ElementSize" + } + ], + "nullable": true + } + } + }, "PaymentLinkConfig": { "type": "object", "required": [ @@ -12601,6 +12690,27 @@ }, "description": "Dynamic details related to merchant to be rendered in payment link", "nullable": true + }, + "background_image": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkBackgroundImageConfig" + } + ], + "nullable": true + }, + "details_layout": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkDetailsLayout" + } + ], + "nullable": true + }, + "branding_visibility": { + "type": "boolean", + "description": "Toggle for HyperSwitch branding visibility", + "nullable": true } } }, @@ -12670,9 +12780,32 @@ }, "description": "Dynamic details related to merchant to be rendered in payment link", "nullable": true + }, + "background_image": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkBackgroundImageConfig" + } + ], + "nullable": true + }, + "details_layout": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkDetailsLayout" + } + ], + "nullable": true } } }, + "PaymentLinkDetailsLayout": { + "type": "string", + "enum": [ + "layout1", + "layout2" + ] + }, "PaymentLinkInitiateRequest": { "type": "object", "required": [ @@ -20016,6 +20149,13 @@ } ] }, + "SizeVariants": { + "type": "string", + "enum": [ + "cover", + "contain" + ] + }, "StraightThroughAlgorithm": { "oneOf": [ { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index ce383f240647..8b06e167e21a 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -7974,6 +7974,11 @@ "description": "A list of allowed domains (glob patterns) where this link can be embedded / opened from", "uniqueItems": true, "nullable": true + }, + "branding_visibility": { + "type": "boolean", + "description": "Toggle for HyperSwitch branding visibility", + "nullable": true } } } @@ -10268,6 +10273,61 @@ "none" ] }, + "ElementPosition": { + "type": "string", + "enum": [ + "left", + "top left", + "top", + "top right", + "right", + "bottom right", + "bottom", + "bottom left", + "center" + ] + }, + "ElementSize": { + "oneOf": [ + { + "type": "object", + "required": [ + "Variants" + ], + "properties": { + "Variants": { + "$ref": "#/components/schemas/SizeVariants" + } + } + }, + { + "type": "object", + "required": [ + "Percentage" + ], + "properties": { + "Percentage": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + }, + { + "type": "object", + "required": [ + "Pixels" + ], + "properties": { + "Pixels": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + } + ] + }, "EnabledPaymentMethod": { "type": "object", "description": "Object for EnabledPaymentMethod", @@ -15255,6 +15315,35 @@ } } }, + "PaymentLinkBackgroundImageConfig": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "URL of the image", + "example": "https://hyperswitch.io/favicon.ico" + }, + "position": { + "allOf": [ + { + "$ref": "#/components/schemas/ElementPosition" + } + ], + "nullable": true + }, + "size": { + "allOf": [ + { + "$ref": "#/components/schemas/ElementSize" + } + ], + "nullable": true + } + } + }, "PaymentLinkConfig": { "type": "object", "required": [ @@ -15316,6 +15405,27 @@ }, "description": "Dynamic details related to merchant to be rendered in payment link", "nullable": true + }, + "background_image": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkBackgroundImageConfig" + } + ], + "nullable": true + }, + "details_layout": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkDetailsLayout" + } + ], + "nullable": true + }, + "branding_visibility": { + "type": "boolean", + "description": "Toggle for HyperSwitch branding visibility", + "nullable": true } } }, @@ -15385,9 +15495,32 @@ }, "description": "Dynamic details related to merchant to be rendered in payment link", "nullable": true + }, + "background_image": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkBackgroundImageConfig" + } + ], + "nullable": true + }, + "details_layout": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentLinkDetailsLayout" + } + ], + "nullable": true } } }, + "PaymentLinkDetailsLayout": { + "type": "string", + "enum": [ + "layout1", + "layout2" + ] + }, "PaymentLinkInitiateRequest": { "type": "object", "required": [ @@ -23934,6 +24067,13 @@ } ] }, + "SizeVariants": { + "type": "string", + "enum": [ + "cover", + "contain" + ] + }, "StraightThroughAlgorithm": { "oneOf": [ { diff --git a/config/deployments/production.toml b/config/deployments/production.toml index 82f9b65b27a7..d4432b7021b9 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -179,7 +179,7 @@ card.credit = { connector_list = "cybersource" } # Update Mandate sup card.debit = { connector_list = "cybersource" } # Update Mandate supported payment method type and connector for card [network_transaction_id_supported_connectors] -connector_list = "stripe,adyen,cybersource" +connector_list = "adyen" [payouts] payout_eligibility = true # Defaults the eligibility of a payout method to true in case connector does not provide checks for payout eligibility diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 769ef5928030..226d39740533 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -2667,6 +2667,8 @@ pub struct BusinessPaymentLinkConfig { /// A list of allowed domains (glob patterns) where this link can be embedded / opened from #[schema(value_type = Option>)] pub allowed_domains: Option>, + /// Toggle for HyperSwitch branding visibility + pub branding_visibility: Option, } impl BusinessPaymentLinkConfig { @@ -2725,6 +2727,11 @@ pub struct PaymentLinkConfigRequest { pub show_card_form_by_default: Option, /// Dynamic details related to merchant to be rendered in payment link pub transaction_details: Option>, + /// Configurations for the background image for details section + pub background_image: Option, + /// Custom layout for details section + #[schema(value_type = Option, example = "layout1")] + pub details_layout: Option, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)] @@ -2752,6 +2759,19 @@ pub struct TransactionDetailsUiConfiguration { pub is_value_bold: Option, } +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, ToSchema)] +pub struct PaymentLinkBackgroundImageConfig { + /// URL of the image + #[schema(value_type = String, example = "https://hyperswitch.io/favicon.ico")] + pub url: common_utils::types::Url, + /// Position of the image in the UI + #[schema(value_type = Option, example = "top-left")] + pub position: Option, + /// Size of the image in the UI + #[schema(value_type = Option, example = "contain")] + pub size: Option, +} + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, ToSchema)] pub struct PaymentLinkConfig { /// custom theme for the payment link @@ -2774,6 +2794,13 @@ pub struct PaymentLinkConfig { pub allowed_domains: Option>, /// Dynamic details related to merchant to be rendered in payment link pub transaction_details: Option>, + /// Configurations for the background image for details section + pub background_image: Option, + /// Custom layout for details section + #[schema(value_type = Option, example = "layout1")] + pub details_layout: Option, + /// Toggle for HyperSwitch branding visibility + pub branding_visibility: Option, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 2114bc9f6ca5..83246d944a31 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -6856,6 +6856,9 @@ pub struct PaymentLinkDetails { pub show_card_form_by_default: bool, pub locale: Option, pub transaction_details: Option>, + pub background_image: Option, + pub details_layout: Option, + pub branding_visibility: Option, } #[derive(Debug, serde::Serialize, Clone)] diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 88c3b6846781..2a74983f2512 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1,8 +1,10 @@ mod payments; +mod ui; use std::num::{ParseFloatError, TryFromIntError}; pub use payments::ProductType; use serde::{Deserialize, Serialize}; +pub use ui::*; use utoipa::ToSchema; pub use super::connector_enums::RoutableConnectors; diff --git a/crates/common_enums/src/enums/ui.rs b/crates/common_enums/src/enums/ui.rs new file mode 100644 index 000000000000..aec6c7ed64a2 --- /dev/null +++ b/crates/common_enums/src/enums/ui.rs @@ -0,0 +1,149 @@ +use std::fmt; + +use serde::{de::Visitor, Deserialize, Deserializer, Serialize}; +use utoipa::ToSchema; + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + Hash, + PartialEq, + Serialize, + Deserialize, + strum::Display, + strum::EnumString, + ToSchema, +)] +#[router_derive::diesel_enum(storage_type = "db_enum")] +#[serde(rename_all = "lowercase")] +pub enum ElementPosition { + Left, + #[default] + #[serde(rename = "top left")] + TopLeft, + Top, + #[serde(rename = "top right")] + TopRight, + Right, + #[serde(rename = "bottom right")] + BottomRight, + Bottom, + #[serde(rename = "bottom left")] + BottomLeft, + Center, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, strum::Display, strum::EnumString, ToSchema)] +#[router_derive::diesel_enum(storage_type = "db_enum")] +pub enum ElementSize { + Variants(SizeVariants), + Percentage(u32), + Pixels(u32), +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + Hash, + PartialEq, + Serialize, + Deserialize, + strum::Display, + strum::EnumString, + ToSchema, +)] +#[router_derive::diesel_enum(storage_type = "db_enum")] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum SizeVariants { + #[default] + Cover, + Contain, +} + +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + Hash, + PartialEq, + Serialize, + Deserialize, + strum::Display, + strum::EnumString, + ToSchema, +)] +#[router_derive::diesel_enum(storage_type = "db_enum")] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum PaymentLinkDetailsLayout { + #[default] + Layout1, + Layout2, +} + +impl<'de> Deserialize<'de> for ElementSize { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ElementSizeVisitor; + + impl Visitor<'_> for ElementSizeVisitor { + type Value = ElementSize; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a string with possible values - contain, cover or values in percentage or pixels. For eg: 48px or 50%") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + if let Some(percent) = value.strip_suffix('%') { + percent + .parse::() + .map(ElementSize::Percentage) + .map_err(E::custom) + } else if let Some(px) = value.strip_suffix("px") { + px.parse::() + .map(ElementSize::Pixels) + .map_err(E::custom) + } else { + match value { + "cover" => Ok(ElementSize::Variants(SizeVariants::Cover)), + "contain" => Ok(ElementSize::Variants(SizeVariants::Contain)), + _ => Err(E::custom("invalid size variant")), + } + } + } + } + + deserializer.deserialize_str(ElementSizeVisitor) + } +} + +impl Serialize for ElementSize { + fn serialize(&self, serializer: S) -> Result + where + S: serde::ser::Serializer, + { + match self { + Self::Variants(variant) => serializer.serialize_str(variant.to_string().as_str()), + Self::Pixels(pixel_count) => { + serializer.serialize_str(format!("{}px", pixel_count).as_str()) + } + Self::Percentage(pixel_count) => { + serializer.serialize_str(format!("{}%", pixel_count).as_str()) + } + } + } +} diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 0cae67873d65..bafd1897200c 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -556,6 +556,7 @@ pub struct BusinessPaymentLinkConfig { pub default_config: Option, pub business_specific_configs: Option>, pub allowed_domains: Option>, + pub branding_visibility: Option, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] @@ -568,6 +569,15 @@ pub struct PaymentLinkConfigRequest { pub enabled_saved_payment_method: Option, pub hide_card_nickname_field: Option, pub show_card_form_by_default: Option, + pub background_image: Option, + pub details_layout: Option, +} + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq)] +pub struct PaymentLinkBackgroundImageConfig { + pub url: common_utils::types::Url, + pub position: Option, + pub size: Option, } common_utils::impl_to_sql_from_sql_json!(BusinessPaymentLinkConfig); diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index b29da50d0a7d..8d037c5356f4 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -4,13 +4,13 @@ use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; -use crate::enums as storage_enums; #[cfg(feature = "v1")] use crate::schema::payment_intent; #[cfg(feature = "v2")] use crate::schema_v2::payment_intent; #[cfg(feature = "v2")] use crate::types::{FeatureMetadata, OrderDetailsWithAmount}; +use crate::{business_profile::PaymentLinkBackgroundImageConfig, enums as storage_enums}; #[cfg(feature = "v2")] #[derive(Clone, Debug, PartialEq, Identifiable, Queryable, Serialize, Deserialize, Selectable)] @@ -161,6 +161,10 @@ pub struct PaymentLinkConfigRequestForPayments { pub show_card_form_by_default: Option, /// Dynamic details related to merchant to be rendered in payment link pub transaction_details: Option>, + /// Configurations for the background image for details section + pub background_image: Option, + /// Custom layout for details section + pub details_layout: Option, } common_utils::impl_to_sql_from_sql_json!(PaymentLinkConfigRequestForPayments); diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index 31732e132868..0e8722644bd4 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -193,6 +193,7 @@ impl ApiModelToDieselModelConvertor enabled_saved_payment_method: item.enabled_saved_payment_method, hide_card_nickname_field: item.hide_card_nickname_field, show_card_form_by_default: item.show_card_form_by_default, + details_layout: item.details_layout, transaction_details: item.transaction_details.map(|transaction_details| { transaction_details .into_iter() @@ -203,6 +204,11 @@ impl ApiModelToDieselModelConvertor }) .collect() }), + background_image: item.background_image.map(|background_image| { + diesel_models::business_profile::PaymentLinkBackgroundImageConfig::convert_from( + background_image, + ) + }), } } fn convert_back(self) -> api_models::admin::PaymentLinkConfigRequest { @@ -216,6 +222,8 @@ impl ApiModelToDieselModelConvertor hide_card_nickname_field, show_card_form_by_default, transaction_details, + background_image, + details_layout, } = self; api_models::admin::PaymentLinkConfigRequest { theme, @@ -226,12 +234,15 @@ impl ApiModelToDieselModelConvertor enabled_saved_payment_method, hide_card_nickname_field, show_card_form_by_default, + details_layout, transaction_details: transaction_details.map(|transaction_details| { transaction_details .into_iter() .map(|transaction_detail| transaction_detail.convert_back()) .collect() }), + background_image: background_image + .map(|background_image| background_image.convert_back()), } } } @@ -264,6 +275,31 @@ impl ApiModelToDieselModelConvertor + for diesel_models::business_profile::PaymentLinkBackgroundImageConfig +{ + fn convert_from(from: api_models::admin::PaymentLinkBackgroundImageConfig) -> Self { + Self { + url: from.url, + position: from.position, + size: from.size, + } + } + fn convert_back(self) -> api_models::admin::PaymentLinkBackgroundImageConfig { + let Self { + url, + position, + size, + } = self; + api_models::admin::PaymentLinkBackgroundImageConfig { + url, + position, + size, + } + } +} + #[cfg(feature = "v2")] impl ApiModelToDieselModelConvertor for diesel_models::TransactionDetailsUiConfiguration diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index d50bf863b5b8..68b0893bcc00 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -286,6 +286,10 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::ReconStatus, api_models::enums::ConnectorStatus, api_models::enums::AuthorizationStatus, + api_models::enums::ElementPosition, + api_models::enums::ElementSize, + api_models::enums::SizeVariants, + api_models::enums::PaymentLinkDetailsLayout, api_models::enums::PaymentMethodStatus, api_models::enums::UIWidgetFormLayout, api_models::admin::MerchantConnectorCreate, @@ -305,6 +309,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::admin::ProfileCreate, api_models::admin::ProfileResponse, api_models::admin::BusinessPaymentLinkConfig, + api_models::admin::PaymentLinkBackgroundImageConfig, api_models::admin::PaymentLinkConfigRequest, api_models::admin::PaymentLinkConfig, api_models::admin::PaymentLinkTransactionDetails, diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 688d749d5d99..e3c9ef0b0155 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -247,6 +247,10 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::ReconStatus, api_models::enums::ConnectorStatus, api_models::enums::AuthorizationStatus, + api_models::enums::ElementPosition, + api_models::enums::ElementSize, + api_models::enums::SizeVariants, + api_models::enums::PaymentLinkDetailsLayout, api_models::enums::PaymentMethodStatus, api_models::enums::OrderFulfillmentTimeOrigin, api_models::enums::UIWidgetFormLayout, @@ -267,6 +271,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::admin::ProfileCreate, api_models::admin::ProfileResponse, api_models::admin::BusinessPaymentLinkConfig, + api_models::admin::PaymentLinkBackgroundImageConfig, api_models::admin::PaymentLinkConfigRequest, api_models::admin::PaymentLinkConfig, api_models::admin::PaymentLinkTransactionDetails, diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs index bc66461e8192..f9522b04d95c 100644 --- a/crates/router/src/core/payment_link.rs +++ b/crates/router/src/core/payment_link.rs @@ -35,7 +35,7 @@ use crate::{ api::payment_link::PaymentLinkResponseExt, domain, storage::{enums as storage_enums, payment_link::PaymentLink}, - transformers::ForeignFrom, + transformers::{ForeignFrom, ForeignInto}, }, }; @@ -129,6 +129,9 @@ pub async fn form_payment_link_data( show_card_form_by_default: DEFAULT_SHOW_CARD_FORM, allowed_domains: DEFAULT_ALLOWED_DOMAINS, transaction_details: None, + background_image: None, + details_layout: None, + branding_visibility: None, } }; @@ -271,6 +274,9 @@ pub async fn form_payment_link_data( show_card_form_by_default: payment_link_config.show_card_form_by_default, locale, transaction_details: payment_link_config.transaction_details.clone(), + background_image: payment_link_config.background_image.clone(), + details_layout: payment_link_config.details_layout, + branding_visibility: payment_link_config.branding_visibility, }; Ok(( @@ -586,18 +592,16 @@ pub fn get_payment_link_config_based_on_priority( default_domain_name: String, payment_link_config_id: Option, ) -> Result<(PaymentLinkConfig, String), error_stack::Report> { - let (domain_name, business_theme_configs, allowed_domains) = + let (domain_name, business_theme_configs, allowed_domains, branding_visibility) = if let Some(business_config) = business_link_config { - logger::info!( - "domain name set to custom domain https://{:?}", - business_config.domain_name - ); - ( business_config .domain_name .clone() - .map(|d_name| format!("https://{}", d_name)) + .map(|d_name| { + logger::info!("domain name set to custom domain https://{:?}", d_name); + format!("https://{}", d_name) + }) .unwrap_or_else(|| default_domain_name.clone()), payment_link_config_id .and_then(|id| { @@ -608,9 +612,10 @@ pub fn get_payment_link_config_based_on_priority( }) .or(business_config.default_config), business_config.allowed_domains, + business_config.branding_visibility, ) } else { - (default_domain_name, None, None) + (default_domain_name, None, None, None) }; let ( @@ -637,19 +642,45 @@ pub fn get_payment_link_config_based_on_priority( (hide_card_nickname_field, DEFAULT_HIDE_CARD_NICKNAME_FIELD), (show_card_form_by_default, DEFAULT_SHOW_CARD_FORM) ); - let payment_link_config = PaymentLinkConfig { - theme, - logo, - seller_name, - sdk_layout, - display_sdk_only, - enabled_saved_payment_method, - hide_card_nickname_field, - show_card_form_by_default, - allowed_domains, - transaction_details: payment_create_link_config - .and_then(|payment_link_config| payment_link_config.theme_config.transaction_details), - }; + let payment_link_config = + PaymentLinkConfig { + theme, + logo, + seller_name, + sdk_layout, + display_sdk_only, + enabled_saved_payment_method, + hide_card_nickname_field, + show_card_form_by_default, + allowed_domains, + branding_visibility, + transaction_details: payment_create_link_config.as_ref().and_then( + |payment_link_config| payment_link_config.theme_config.transaction_details.clone(), + ), + details_layout: payment_create_link_config + .as_ref() + .and_then(|payment_link_config| payment_link_config.theme_config.details_layout) + .or_else(|| { + business_theme_configs + .as_ref() + .and_then(|business_theme_config| business_theme_config.details_layout) + }), + background_image: payment_create_link_config + .as_ref() + .and_then(|payment_link_config| { + payment_link_config.theme_config.background_image.clone() + }) + .or_else(|| { + business_theme_configs + .as_ref() + .and_then(|business_theme_config| { + business_theme_config + .background_image + .as_ref() + .map(|background_image| background_image.clone().foreign_into()) + }) + }), + }; Ok((payment_link_config, domain_name)) } @@ -752,6 +783,9 @@ pub async fn get_payment_link_status( show_card_form_by_default: DEFAULT_SHOW_CARD_FORM, allowed_domains: DEFAULT_ALLOWED_DOMAINS, transaction_details: None, + background_image: None, + details_layout: None, + branding_visibility: None, } }; diff --git a/crates/router/src/core/payment_link/payment_link_initiate/payment_link.css b/crates/router/src/core/payment_link/payment_link_initiate/payment_link.css index 65a50e967f3b..b8ccdeba33aa 100644 --- a/crates/router/src/core/payment_link/payment_link_initiate/payment_link.css +++ b/crates/router/src/core/payment_link/payment_link_initiate/payment_link.css @@ -71,6 +71,7 @@ body { #hyper-checkout-details { font-family: "Montserrat"; + background-repeat: no-repeat; } .hyper-checkout-payment { @@ -144,7 +145,7 @@ body { #hyper-checkout-merchant-image, #hyper-checkout-cart-image { height: 64px; - width: 64px; + padding: 0 10px; border-radius: 4px; display: flex; align-self: flex-start; @@ -153,8 +154,7 @@ body { } #hyper-checkout-merchant-image > img { - height: 48px; - width: 48px; + height: 40px; } #hyper-checkout-cart-image { @@ -279,7 +279,7 @@ body { #hyper-checkout-merchant-description { font-size: 13px; - color: #808080; + margin: 10px 0 20px 0; } .powered-by-hyper { @@ -292,7 +292,6 @@ body { min-width: 584px; z-index: 2; background-color: var(--primary-color); - box-shadow: 0px 1px 10px #f2f2f2; display: flex; flex-flow: column; align-items: center; @@ -665,6 +664,12 @@ body { animation: loading 1s linear infinite; } +@media only screen and (min-width: 1199px) { + #hyper-checkout-merchant-description { + color: #808080; + } +} + @media only screen and (max-width: 1199px) { body { overflow-y: scroll; diff --git a/crates/router/src/core/payment_link/payment_link_initiate/payment_link.html b/crates/router/src/core/payment_link/payment_link_initiate/payment_link.html index 963b4d6083a6..9abcc440068a 100644 --- a/crates/router/src/core/payment_link/payment_link_initiate/payment_link.html +++ b/crates/router/src/core/payment_link/payment_link_initiate/payment_link.html @@ -185,7 +185,7 @@
-
+
@@ -313,17 +301,6 @@
-