diff --git a/config/config.example.toml b/config/config.example.toml index 8f7ea8a992..8cbabb639c 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -228,6 +228,7 @@ volt.base_url = "https://api.sandbox.volt.io/" wise.base_url = "https://api.sandbox.transferwise.tech/" worldline.base_url = "https://eu.sandbox.api-ingenico.com/" worldpay.base_url = "https://try.access.worldpay.com/" +zsl.base_url = "https://api.sitoffalb.net/" zen.base_url = "https://api.zen-test.com/" zen.secondary_base_url = "https://secure.zen-test.com/" @@ -280,6 +281,7 @@ cards = [ "threedsecureio", "worldpay", "zen", + "zsl", ] # Scheduler settings provides a point to modify the behaviour of scheduler flow. diff --git a/config/development.toml b/config/development.toml index f5bd1c1ab3..b030d8c932 100644 --- a/config/development.toml +++ b/config/development.toml @@ -143,6 +143,7 @@ cards = [ "worldline", "worldpay", "zen", + "zsl", ] [refund] @@ -227,6 +228,7 @@ volt.base_url = "https://api.sandbox.volt.io/" trustpay.base_url_bank_redirects = "https://aapi.trustpay.eu/" zen.base_url = "https://api.zen-test.com/" zen.secondary_base_url = "https://secure.zen-test.com/" +zsl.base_url = "https://api.sitoffalb.net/" [scheduler] stream = "SCHEDULER_STREAM" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 44594cd765..29d426c288 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -164,6 +164,7 @@ worldline.base_url = "https://eu.sandbox.api-ingenico.com/" worldpay.base_url = "https://try.access.worldpay.com/" zen.base_url = "https://api.zen-test.com/" zen.secondary_base_url = "https://secure.zen-test.com/" +zsl.base_url = "https://api.sitoffalb.net/" [pm_filters.default] @@ -225,6 +226,7 @@ cards = [ "worldline", "worldpay", "zen", + "zsl" ] [delayed_session_response] diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 60d8a9a984..3eb7a1f2b3 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -126,10 +126,11 @@ pub enum Connector { Wise, Worldline, Worldpay, - Zen, Signifyd, Plaid, Riskified, + Zen, + // Zsl, Added as template code for future usage } impl Connector { @@ -207,6 +208,7 @@ impl Connector { | Self::Worldline | Self::Worldpay | Self::Zen + // | Self::Zsl Added as template code for future usage | Self::Signifyd | Self::Plaid | Self::Riskified @@ -264,6 +266,7 @@ impl Connector { | Self::Worldline | Self::Worldpay | Self::Zen + // | Self::Zsl, Added as template code for future usage | Self::Signifyd | Self::Plaid | Self::Riskified diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 1134d072c2..d8a86d7563 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -167,6 +167,7 @@ pub enum RoutableConnectors { Worldline, Worldpay, Zen, + // Zsl, Added as template code for future usage } impl AttemptStatus { diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs index 5a67847a9e..6e2cce946a 100644 --- a/crates/connector_configs/src/connector.rs +++ b/crates/connector_configs/src/connector.rs @@ -163,12 +163,13 @@ pub struct ConnectorConfig { pub wise_payout: Option, pub worldline: Option, pub worldpay: Option, - pub zen: Option, pub square: Option, pub stax: Option, pub dummy_connector: Option, pub stripe_test: Option, pub paypal_test: Option, + pub zen: Option, + pub zsl: Option, } impl ConnectorConfig { @@ -277,6 +278,7 @@ impl ConnectorConfig { Connector::Worldline => Ok(connector_data.worldline), Connector::Worldpay => Ok(connector_data.worldpay), Connector::Zen => Ok(connector_data.zen), + // Connector::Zsl => Ok(connector_data.zsl), Added as template code for future usage #[cfg(feature = "dummy_connector")] Connector::DummyConnector1 => Ok(connector_data.dummy_connector), #[cfg(feature = "dummy_connector")] diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index a15f9a1115..74598f0a5c 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -539,6 +539,7 @@ pub struct Connectors { pub worldline: ConnectorParams, pub worldpay: ConnectorParams, pub zen: ConnectorParams, + pub zsl: ConnectorParams, } #[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)] diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index 3c63aab54b..c7a6256d85 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -57,6 +57,7 @@ pub mod wise; pub mod worldline; pub mod worldpay; pub mod zen; +pub mod zsl; #[cfg(feature = "dummy_connector")] pub use self::dummyconnector::DummyConnector; @@ -72,5 +73,5 @@ pub use self::{ payu::Payu, placetopay::Placetopay, powertranz::Powertranz, prophetpay::Prophetpay, rapyd::Rapyd, riskified::Riskified, shift4::Shift4, signifyd::Signifyd, square::Square, stax::Stax, stripe::Stripe, threedsecureio::Threedsecureio, trustpay::Trustpay, tsys::Tsys, - volt::Volt, wise::Wise, worldline::Worldline, worldpay::Worldpay, zen::Zen, + volt::Volt, wise::Wise, worldline::Worldline, worldpay::Worldpay, zen::Zen, zsl::Zsl, }; diff --git a/crates/router/src/connector/zsl.rs b/crates/router/src/connector/zsl.rs new file mode 100644 index 0000000000..5453a22ecb --- /dev/null +++ b/crates/router/src/connector/zsl.rs @@ -0,0 +1,279 @@ +pub mod transformers; + +use std::fmt::Debug; + +use error_stack::{report, ResultExt}; +use masking::ExposeInterface; +use transformers as zsl; + +use crate::{ + configs::settings, + core::errors::{self, CustomResult}, + events::connector_api_logs::ConnectorEvent, + headers, + services::{ + self, + request::{self, Mask}, + ConnectorIntegration, ConnectorValidation, + }, + types::{ + self, + api::{self, ConnectorCommon, ConnectorCommonExt}, + ErrorResponse, RequestContent, Response, + }, + utils::BytesExt, +}; + +#[derive(Debug, Clone)] +pub struct Zsl; + +impl api::Payment for Zsl {} +impl api::PaymentSession for Zsl {} +impl api::ConnectorAccessToken for Zsl {} +impl api::MandateSetup for Zsl {} +impl api::PaymentAuthorize for Zsl {} +impl api::PaymentSync for Zsl {} +impl api::PaymentCapture for Zsl {} +impl api::PaymentVoid for Zsl {} +impl api::Refund for Zsl {} +impl api::RefundExecute for Zsl {} +impl api::RefundSync for Zsl {} +impl api::PaymentToken for Zsl {} + +impl + ConnectorIntegration< + api::PaymentMethodToken, + types::PaymentMethodTokenizationData, + types::PaymentsResponseData, + > for Zsl +{ + // Not Implemented (R) +} + +impl ConnectorCommonExt for Zsl +where + Self: ConnectorIntegration, +{ + fn build_headers( + &self, + req: &types::RouterData, + _connectors: &settings::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 Zsl { + fn id(&self) -> &'static str { + "zsl" + } + + fn get_currency_unit(&self) -> api::CurrencyUnit { + api::CurrencyUnit::Minor + } + + fn common_get_content_type(&self) -> &'static str { + "application/json" + } + + fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + connectors.zsl.base_url.as_ref() + } + + fn get_auth_header( + &self, + auth_type: &types::ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { + let auth = zsl::ZslAuthType::try_from(auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + + Ok(vec![( + headers::AUTHORIZATION.to_string(), + format!("{}:{}", auth.api_key.expose(), auth.merchant_id.expose()).into_masked(), + )]) + } + + fn build_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + let response: zsl::ZslErrorResponse = res + .response + .parse_struct("ZslErrorResponse") + .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 Zsl { + //TODO: implement functions when support enabled +} + +impl ConnectorIntegration + for Zsl +{ + //TODO: implement sessions flow +} + +impl ConnectorIntegration + for Zsl +{ +} + +impl + ConnectorIntegration< + api::SetupMandate, + types::SetupMandateRequestData, + types::PaymentsResponseData, + > for Zsl +{ +} + +impl ConnectorIntegration + for Zsl +{ + fn get_headers( + &self, + req: &types::PaymentsAuthorizeRouterData, + connectors: &settings::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: &types::PaymentsAuthorizeRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + req: &types::PaymentsAuthorizeRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + let connector_router_data = zsl::ZslRouterData::try_from(( + &self.get_currency_unit(), + req.request.currency, + req.request.amount, + req, + ))?; + let connector_req = zsl::ZslPaymentsRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) + } + + fn build_request( + &self, + req: &types::PaymentsAuthorizeRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + services::RequestBuilder::new() + .method(services::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: &types::PaymentsAuthorizeRouterData, + event_builder: Option<&mut ConnectorEvent>, + res: Response, + ) -> CustomResult { + let response: zsl::ZslPaymentsResponse = res + .response + .parse_struct("Zsl 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 { + 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 Zsl +{ +} + +impl ConnectorIntegration + for Zsl +{ +} + +impl ConnectorIntegration + for Zsl +{ +} + +impl ConnectorIntegration for Zsl {} + +impl ConnectorIntegration for Zsl {} + +#[async_trait::async_trait] +impl api::IncomingWebhook for Zsl { + fn get_webhook_object_reference_id( + &self, + _request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_event_type( + &self, + _request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_resource_object( + &self, + _request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult, errors::ConnectorError> { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } +} diff --git a/crates/router/src/connector/zsl/transformers.rs b/crates/router/src/connector/zsl/transformers.rs new file mode 100644 index 0000000000..f14f0279cb --- /dev/null +++ b/crates/router/src/connector/zsl/transformers.rs @@ -0,0 +1,159 @@ +use masking::Secret; +use serde::{Deserialize, Serialize}; + +use crate::{ + connector::utils::PaymentsAuthorizeRequestData, + core::errors, + types::{self, domain, storage::enums}, +}; + +//TODO: Fill the struct with respective fields +pub struct ZslRouterData { + pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub router_data: T, +} + +impl + TryFrom<( + &types::api::CurrencyUnit, + types::storage::enums::Currency, + i64, + T, + )> for ZslRouterData +{ + type Error = error_stack::Report; + fn try_from( + (_currency_unit, _currency, amount, item): ( + &types::api::CurrencyUnit, + types::storage::enums::Currency, + i64, + T, + ), + ) -> Result { + //Todo : use utils to convert the amount to the type of amount that a connector accepts + Ok(Self { + amount, + router_data: item, + }) + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct ZslPaymentsRequest { + amount: i64, + card: ZslCard, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct ZslCard { + number: cards::CardNumber, + expiry_month: Secret, + expiry_year: Secret, + cvc: Secret, + complete: bool, +} + +impl TryFrom<&ZslRouterData<&types::PaymentsAuthorizeRouterData>> for ZslPaymentsRequest { + type Error = error_stack::Report; + fn try_from( + item: &ZslRouterData<&types::PaymentsAuthorizeRouterData>, + ) -> Result { + match item.router_data.request.payment_method_data.clone() { + domain::PaymentMethodData::Card(req_card) => { + let card = ZslCard { + 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.to_owned(), + card, + }) + } + _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), + } + } +} + +//TODO: Fill the struct with respective fields +// Auth Struct +pub struct ZslAuthType { + pub(super) api_key: Secret, + pub(super) merchant_id: Secret, +} + +impl TryFrom<&types::ConnectorAuthType> for ZslAuthType { + type Error = error_stack::Report; + fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + match auth_type { + types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { + api_key: api_key.to_owned(), + merchant_id: key1.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 ZslPaymentStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +impl From for enums::AttemptStatus { + fn from(item: ZslPaymentStatus) -> Self { + match item { + ZslPaymentStatus::Succeeded => Self::Charged, + ZslPaymentStatus::Failed => Self::Failure, + ZslPaymentStatus::Processing => Self::Authorizing, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct ZslPaymentsResponse { + status: ZslPaymentStatus, + id: String, +} + +impl + TryFrom> + for types::RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::ResponseRouterData, + ) -> Result { + Ok(Self { + status: enums::AttemptStatus::from(item.response.status), + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), + redirection_data: None, + mandate_reference: None, + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct ZslErrorResponse { + pub status_code: u16, + pub code: String, + pub message: String, + pub reason: Option, +} diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index ab402f3a89..eaa63f1b2f 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1916,6 +1916,10 @@ pub(crate) fn validate_auth_and_metadata_type( zen::transformers::ZenAuthType::try_from(val)?; Ok(()) } + // api_enums::Connector::Zsl => { + // zsl::transformers::ZslAuthType::try_from(val)?; + // Ok(()) + // } Added as template code for future usage api_enums::Connector::Signifyd => { signifyd::transformers::SignifydAuthType::try_from(val)?; Ok(()) diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 2e8713fbdb..3f8d56a372 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -185,7 +185,8 @@ default_imp_for_complete_authorize!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_webhook_source_verification { ($($path:ident::$connector:ident),*) => { @@ -268,7 +269,8 @@ default_imp_for_webhook_source_verification!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_create_customer { @@ -351,7 +353,8 @@ default_imp_for_create_customer!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_connector_redirect_response { @@ -423,7 +426,8 @@ default_imp_for_connector_redirect_response!( connector::Volt, connector::Wise, connector::Worldline, - connector::Worldpay + connector::Worldpay, + connector::Zsl ); macro_rules! default_imp_for_connector_request_id { @@ -438,6 +442,7 @@ macro_rules! default_imp_for_connector_request_id { impl api::ConnectorTransactionId for connector::DummyConnector {} default_imp_for_connector_request_id!( + connector::Zsl, connector::Aci, connector::Adyen, connector::Airwallex, @@ -579,7 +584,8 @@ default_imp_for_accept_dispute!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_file_upload { @@ -685,7 +691,8 @@ default_imp_for_file_upload!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_submit_evidence { @@ -769,7 +776,8 @@ default_imp_for_submit_evidence!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_defend_dispute { @@ -854,7 +862,8 @@ default_imp_for_defend_dispute!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_pre_processing_steps{ @@ -931,7 +940,8 @@ default_imp_for_pre_processing_steps!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_payouts { @@ -999,7 +1009,8 @@ default_imp_for_payouts!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "payouts")] @@ -1084,7 +1095,8 @@ default_imp_for_payouts_create!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "payouts")] @@ -1172,7 +1184,8 @@ default_imp_for_payouts_eligibility!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "payouts")] @@ -1257,7 +1270,8 @@ default_imp_for_payouts_fulfill!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "payouts")] @@ -1342,7 +1356,8 @@ default_imp_for_payouts_cancel!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "payouts")] @@ -1428,7 +1443,8 @@ default_imp_for_payouts_quote!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "payouts")] @@ -1514,7 +1530,8 @@ default_imp_for_payouts_recipient!( connector::Volt, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_approve { @@ -1600,7 +1617,8 @@ default_imp_for_approve!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_reject { @@ -1686,7 +1704,8 @@ default_imp_for_reject!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_fraud_check { @@ -1754,7 +1773,8 @@ default_imp_for_fraud_check!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "frm")] @@ -1840,7 +1860,8 @@ default_imp_for_frm_sale!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "frm")] @@ -1926,7 +1947,8 @@ default_imp_for_frm_checkout!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "frm")] @@ -2012,7 +2034,8 @@ default_imp_for_frm_transaction!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "frm")] @@ -2098,7 +2121,8 @@ default_imp_for_frm_fulfillment!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); #[cfg(feature = "frm")] @@ -2184,7 +2208,8 @@ default_imp_for_frm_record_return!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_incremental_authorization { @@ -2269,7 +2294,8 @@ default_imp_for_incremental_authorization!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_revoking_mandates { @@ -2351,7 +2377,8 @@ default_imp_for_revoking_mandates!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); macro_rules! default_imp_for_connector_authentication { @@ -2476,5 +2503,6 @@ default_imp_for_connector_authentication!( connector::Wise, connector::Worldline, connector::Worldpay, - connector::Zen + connector::Zen, + connector::Zsl ); diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index b5a4d04c92..bc75f794c7 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -385,6 +385,7 @@ impl ConnectorData { enums::Connector::Tsys => Ok(Box::new(&connector::Tsys)), enums::Connector::Volt => Ok(Box::new(&connector::Volt)), enums::Connector::Zen => Ok(Box::new(&connector::Zen)), + // enums::Connector::Zsl => Ok(Box::new(&connector::Zsl)), Added as template code for future usage enums::Connector::Signifyd | enums::Connector::Plaid | enums::Connector::Riskified diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index c5250b0cc7..34941d8998 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -247,6 +247,7 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { api_enums::Connector::Worldline => Self::Worldline, api_enums::Connector::Worldpay => Self::Worldpay, api_enums::Connector::Zen => Self::Zen, + // api_enums::Connector::Zsl => Self::Zsl, Added as template code for future usage #[cfg(feature = "dummy_connector")] api_enums::Connector::DummyConnector1 => Self::DummyConnector1, #[cfg(feature = "dummy_connector")] diff --git a/crates/router/tests/connectors/ebanx.rs b/crates/router/tests/connectors/ebanx.rs index 5ef703469e..0c675be224 100644 --- a/crates/router/tests/connectors/ebanx.rs +++ b/crates/router/tests/connectors/ebanx.rs @@ -306,7 +306,7 @@ async fn should_sync_refund() { ); } -// Cards Negative scenerios +// Cards Negative scenarios // Creates a payment with incorrect CVC. #[actix_web::test] async fn should_fail_payment_for_incorrect_cvc() { diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs index 1033953776..92921acfff 100644 --- a/crates/router/tests/connectors/main.rs +++ b/crates/router/tests/connectors/main.rs @@ -65,3 +65,4 @@ mod wise; mod worldline; mod worldpay; mod zen; +mod zsl; diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index 5502629a8a..6f260de51d 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -206,3 +206,9 @@ api_key="API Key" [ebanx] api_key="API Key" + + +[zsl] +api_key="API Key" +key1= "Merchant id" + diff --git a/crates/router/tests/connectors/zsl.rs b/crates/router/tests/connectors/zsl.rs new file mode 100644 index 0000000000..21942020cf --- /dev/null +++ b/crates/router/tests/connectors/zsl.rs @@ -0,0 +1,59 @@ +use router::types::{self, storage::enums}; +use test_utils::connector_auth; + +use crate::utils::{self, ConnectorActions}; + +struct ZslTest; +impl ConnectorActions for ZslTest {} +impl utils::Connector for ZslTest { + fn get_data(&self) -> types::api::ConnectorData { + use router::connector::Zsl; + types::api::ConnectorData { + connector: Box::new(&Zsl), + connector_name: types::Connector::Adyen, + // Added as Dummy connector as template code is added for future usage + get_token: types::api::GetToken::Connector, + merchant_connector_id: None, + } + } + + fn get_auth_token(&self) -> types::ConnectorAuthType { + utils::to_connector_auth_type( + connector_auth::ConnectorAuthentication::new() + .zsl + .expect("Missing connector authentication configuration") + .into(), + ) + } + + fn get_name(&self) -> String { + "zsl".to_string() + } +} + +static CONNECTOR: ZslTest = ZslTest {}; + +fn get_default_payment_info() -> Option { + None +} + +fn payment_method_details() -> Option { + None +} + +// 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::AuthenticationPending); +} diff --git a/crates/test_utils/src/connector_auth.rs b/crates/test_utils/src/connector_auth.rs index 6666f9883f..85114699e9 100644 --- a/crates/test_utils/src/connector_auth.rs +++ b/crates/test_utils/src/connector_auth.rs @@ -68,6 +68,7 @@ pub struct ConnectorAuthentication { pub worldpay: Option, pub worldline: Option, pub zen: Option, + pub zsl: Option, pub automation_configs: Option, } diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index 3a71072910..66c1c855d3 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -131,6 +131,7 @@ worldpay.base_url = "https://try.access.worldpay.com/" wise.base_url = "https://api.sandbox.transferwise.tech/" zen.base_url = "https://api.zen-test.com/" zen.secondary_base_url = "https://secure.zen-test.com/" +zsl.base_url = "https://api.sitoffalb.net/" [pm_filters.default] apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US,KR,VN,MA,ZA,VA,CL,SV,GT,HN,PA", currency = "AED,AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" } @@ -191,6 +192,7 @@ cards = [ "worldline", "worldpay", "zen", + "zsl", ] [pm_filters.volt] diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index c295a54e80..99770c7ff9 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7179,10 +7179,10 @@ "wise", "worldline", "worldpay", - "zen", "signifyd", "plaid", - "riskified" + "riskified", + "zen" ] }, "ConnectorMetadata": { diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh index c05eb558af..440a37a726 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 airwallex applepay authorizedotnet bambora bankofamerica billwerk bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource dlocal dummyconnector ebanx fiserv forte globalpay globepay gocardless helcim iatapay klarna mollie multisafepay nexinets noon nuvei opayo opennode payeezy payme paypal payu placetopay powertranz prophetpay rapyd shift4 square stax stripe threedsecureio trustpay tsys volt wise worldline worldpay "$1") + connectors=(aci adyen airwallex applepay authorizedotnet bambora bankofamerica billwerk bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource dlocal dummyconnector ebanx fiserv forte globalpay globepay gocardless helcim iatapay klarna mollie multisafepay nexinets noon nuvei opayo opennode payeezy payme paypal payu placetopay powertranz prophetpay rapyd shift4 square stax stripe threedsecureio trustpay tsys volt wise worldline worldpay zsl "$1") IFS=$'\n' sorted=($(sort <<<"${connectors[*]}")); unset IFS res=`echo ${sorted[@]}` sed -i'' -e "s/^ connectors=.*/ connectors=($res \"\$1\")/" $self.tmp