diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 8974f940ba..0498c52cd3 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -3577,6 +3577,7 @@ "noon", "nuvei", "opennode", + "paybox", "payme", "payone", "paypal", @@ -15493,6 +15494,7 @@ "noon", "nuvei", "opennode", + "paybox", "payme", "payone", "paypal", diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index b2383e2cb8..7c35d6e4c3 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -8055,6 +8055,7 @@ "noon", "nuvei", "opennode", + "paybox", "payme", "payone", "paypal", @@ -20765,6 +20766,7 @@ "noon", "nuvei", "opennode", + "paybox", "payme", "payone", "paypal", diff --git a/config/deployments/production.toml b/config/deployments/production.toml index b27f3696e3..bac5ec206e 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -70,7 +70,7 @@ noon.key_mode = "Live" nuvei.base_url = "https://ppp-test.nuvei.com/" opayo.base_url = "https://pi-live.sagepay.com/" opennode.base_url = "https://api.opennode.com" -paybox.base_url = "https://preprod-ppps.paybox.com/PPPS.php" +paybox.base_url = "https://ppps.paybox.com/PPPS.php" payeezy.base_url = "https://api.payeezy.com/" payme.base_url = "https://live.payme.io/" payone.base_url = "https://payment.payone.com/" diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 06ac98f59d..a7738133ca 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -116,7 +116,7 @@ pub enum Connector { Nuvei, // Opayo, added as template code for future usage Opennode, - // Paybox, added as template code for future usage + Paybox, // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage Payme, Payone, @@ -244,8 +244,8 @@ impl Connector { | Self::Nexinets | Self::Nuvei | Self::Opennode - // | Self::Paybox added as template code for future usage - | Self::Payme + | Self::Paybox + | Self::Payme | Self::Payone | Self::Paypal | Self::Payu diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 015bf2d6c6..f4807bd0b0 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -229,7 +229,7 @@ pub enum RoutableConnectors { // Opayo, added as template code for future usage Opennode, // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage - // Paybox, added as template code for future usage + Paybox, Payme, Payone, Paypal, diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs index 6cc32fe955..51713f6166 100644 --- a/crates/connector_configs/src/connector.rs +++ b/crates/connector_configs/src/connector.rs @@ -175,7 +175,7 @@ pub struct ConnectorConfig { pub nmi: Option, pub noon: Option, pub nuvei: Option, - // pub paybox: Option, added for future usage + pub paybox: Option, pub payme: Option, #[cfg(feature = "payouts")] pub payone_payout: Option, @@ -323,6 +323,7 @@ impl ConnectorConfig { Connector::Nmi => Ok(connector_data.nmi), Connector::Noon => Ok(connector_data.noon), Connector::Nuvei => Ok(connector_data.nuvei), + Connector::Paybox => Ok(connector_data.paybox), Connector::Payme => Ok(connector_data.payme), Connector::Payone => Err("Use get_payout_connector_config".to_string()), Connector::Paypal => Ok(connector_data.paypal), @@ -363,7 +364,6 @@ impl ConnectorConfig { #[cfg(feature = "dummy_connector")] Connector::DummyConnector7 => Ok(connector_data.paypal_test), Connector::Netcetera => Ok(connector_data.netcetera), - // Connector::Paybox => Ok(connector_data.paybox), added for future usage } } } diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml index 95b22f8f77..cc2ad85e56 100644 --- a/crates/connector_configs/toml/development.toml +++ b/crates/connector_configs/toml/development.toml @@ -3803,6 +3803,46 @@ key1="Public Api Key" api_key = "Passcode" key1 = "datatrans MerchantId" +[paybox] +[[paybox.credit]] + payment_method_type = "Mastercard" +[[paybox.credit]] + payment_method_type = "Visa" +[[paybox.credit]] + payment_method_type = "Interac" +[[paybox.credit]] + payment_method_type = "AmericanExpress" +[[paybox.credit]] + payment_method_type = "JCB" +[[paybox.credit]] + payment_method_type = "DinersClub" +[[paybox.credit]] + payment_method_type = "Discover" +[[paybox.credit]] + payment_method_type = "CartesBancaires" +[[paybox.credit]] + payment_method_type = "UnionPay" +[[paybox.debit]] + payment_method_type = "Mastercard" +[[paybox.debit]] + payment_method_type = "Visa" +[[paybox.debit]] + payment_method_type = "Interac" +[[paybox.debit]] + payment_method_type = "AmericanExpress" +[[paybox.debit]] + payment_method_type = "JCB" +[[paybox.debit]] + payment_method_type = "DinersClub" +[[paybox.debit]] + payment_method_type = "Discover" +[[paybox.debit]] + payment_method_type = "CartesBancaires" +[paybox.connector_auth.SignatureKey] +api_key="SITE Key" +key1="Rang Identifier" +api_secret="CLE Secret" + [wellsfargo] [[wellsfargo.credit]] payment_method_type = "Mastercard" diff --git a/crates/connector_configs/toml/production.toml b/crates/connector_configs/toml/production.toml index a2c118f572..a61911b9da 100644 --- a/crates/connector_configs/toml/production.toml +++ b/crates/connector_configs/toml/production.toml @@ -2680,6 +2680,46 @@ key1 = "Merchant ID" api_key="Private Api Key" key1="Public Api Key" +[paybox] +[[paybox.credit]] + payment_method_type = "Mastercard" +[[paybox.credit]] + payment_method_type = "Visa" +[[paybox.credit]] + payment_method_type = "Interac" +[[paybox.credit]] + payment_method_type = "AmericanExpress" +[[paybox.credit]] + payment_method_type = "JCB" +[[paybox.credit]] + payment_method_type = "DinersClub" +[[paybox.credit]] + payment_method_type = "Discover" +[[paybox.credit]] + payment_method_type = "CartesBancaires" +[[paybox.credit]] + payment_method_type = "UnionPay" +[[paybox.debit]] + payment_method_type = "Mastercard" +[[paybox.debit]] + payment_method_type = "Visa" +[[paybox.debit]] + payment_method_type = "Interac" +[[paybox.debit]] + payment_method_type = "AmericanExpress" +[[paybox.debit]] + payment_method_type = "JCB" +[[paybox.debit]] + payment_method_type = "DinersClub" +[[paybox.debit]] + payment_method_type = "Discover" +[[paybox.debit]] + payment_method_type = "CartesBancaires" +[paybox.connector_auth.SignatureKey] +api_key="SITE Key" +key1="Rang Identifier" +api_secret="CLE Secret" + [datatrans] [[datatrans.credit]] payment_method_type = "Mastercard" diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml index 1c4b61db41..b61187def7 100644 --- a/crates/connector_configs/toml/sandbox.toml +++ b/crates/connector_configs/toml/sandbox.toml @@ -3796,6 +3796,46 @@ key1="Public Api Key" api_key = "Passcode" key1 = "datatrans MerchantId" +[paybox] +[[paybox.credit]] + payment_method_type = "Mastercard" +[[paybox.credit]] + payment_method_type = "Visa" +[[paybox.credit]] + payment_method_type = "Interac" +[[paybox.credit]] + payment_method_type = "AmericanExpress" +[[paybox.credit]] + payment_method_type = "JCB" +[[paybox.credit]] + payment_method_type = "DinersClub" +[[paybox.credit]] + payment_method_type = "Discover" +[[paybox.credit]] + payment_method_type = "CartesBancaires" +[[paybox.credit]] + payment_method_type = "UnionPay" +[[paybox.debit]] + payment_method_type = "Mastercard" +[[paybox.debit]] + payment_method_type = "Visa" +[[paybox.debit]] + payment_method_type = "Interac" +[[paybox.debit]] + payment_method_type = "AmericanExpress" +[[paybox.debit]] + payment_method_type = "JCB" +[[paybox.debit]] + payment_method_type = "DinersClub" +[[paybox.debit]] + payment_method_type = "Discover" +[[paybox.debit]] + payment_method_type = "CartesBancaires" +[paybox.connector_auth.SignatureKey] +api_key="SITE Key" +key1="Rang Identifier" +api_secret="CLE Secret" + [wellsfargo] [[wellsfargo.credit]] payment_method_type = "Mastercard" diff --git a/crates/router/src/connector/paybox.rs b/crates/router/src/connector/paybox.rs index 720f0a00c6..0a7f74a048 100644 --- a/crates/router/src/connector/paybox.rs +++ b/crates/router/src/connector/paybox.rs @@ -1,5 +1,6 @@ pub mod transformers; +use common_enums::enums; use common_utils::types::{AmountConvertor, MinorUnit, MinorUnitForConnector}; use error_stack::{report, ResultExt}; use masking::ExposeInterface; @@ -8,6 +9,7 @@ use transformers as paybox; use super::utils::{self as connector_utils}; use crate::{ configs::settings, + connector::utils, core::errors::{self, CustomResult}, events::connector_api_logs::ConnectorEvent, headers, @@ -49,6 +51,10 @@ impl api::Refund for Paybox {} impl api::RefundExecute for Paybox {} impl api::RefundSync for Paybox {} impl api::PaymentToken for Paybox {} +impl ConnectorIntegration + for Paybox +{ +} impl ConnectorIntegration< @@ -57,7 +63,6 @@ impl types::PaymentsResponseData, > for Paybox { - // Not Implemented (R) } impl ConnectorCommonExt for Paybox @@ -66,15 +71,13 @@ where { fn build_headers( &self, - req: &types::RouterData, + _req: &types::RouterData, _connectors: &settings::Connectors, ) -> CustomResult)>, errors::ConnectorError> { - let mut header = vec![( + let 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) } } @@ -84,15 +87,8 @@ impl ConnectorCommon for Paybox { "paybox" } - // fn get_currency_unit(&self) -> api::CurrencyUnit { - // // todo!() - // // 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" + "application/x-www-form-urlencoded" } fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { @@ -107,7 +103,7 @@ impl ConnectorCommon for Paybox { .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( headers::AUTHORIZATION.to_string(), - auth.api_key.expose().into_masked(), + auth.cle.expose().into_masked(), )]) } @@ -136,13 +132,24 @@ impl ConnectorCommon for Paybox { } impl ConnectorValidation for Paybox { - //TODO: implement functions when support enabled + fn validate_capture_method( + &self, + capture_method: Option, + _pmt: Option, + ) -> CustomResult<(), errors::ConnectorError> { + let capture_method = capture_method.unwrap_or_default(); + match capture_method { + enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()), + enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( + utils::construct_not_implemented_error_report(capture_method, self.id()), + ), + } + } } impl ConnectorIntegration for Paybox { - //TODO: implement sessions flow } impl ConnectorIntegration @@ -158,7 +165,6 @@ impl > for Paybox { } - impl ConnectorIntegration for Paybox { @@ -177,9 +183,9 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(self.base_url(connectors).to_string()) } fn get_request_body( @@ -195,7 +201,7 @@ impl ConnectorIntegration, res: Response, ) -> CustomResult { - let response: paybox::PayboxPaymentsResponse = res - .response - .parse_struct("Paybox PaymentsAuthorizeResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let response: paybox::PayboxResponse = 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 { @@ -262,13 +262,20 @@ impl ConnectorIntegration &'static str { self.common_get_content_type() } - + fn get_request_body( + &self, + req: &types::PaymentsSyncRouterData, + _connectors: &settings::Connectors, + ) -> 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, + connectors: &settings::Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(self.base_url(connectors).to_string()) } fn build_request( @@ -278,10 +285,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { Ok(Some( services::RequestBuilder::new() - .method(services::Method::Get) + .method(services::Method::Post) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) + .set_body(types::PaymentsSyncType::get_request_body( + self, req, connectors, + )?) .build(), )) } @@ -292,10 +301,8 @@ impl ConnectorIntegration, res: Response, ) -> CustomResult { - let response: paybox::PayboxPaymentsResponse = res - .response - .parse_struct("paybox PaymentsSyncResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + 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 { @@ -332,17 +339,25 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(self.base_url(connectors).to_string()) } fn get_request_body( &self, - _req: &types::PaymentsCaptureRouterData, + req: &types::PaymentsCaptureRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + + let connector_router_data = paybox::PayboxRouterData::from((amount, req)); + let connector_req = paybox::PayboxCaptureRequest::try_from(&connector_router_data)?; + Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } fn build_request( @@ -355,9 +370,6 @@ impl ConnectorIntegration, res: Response, ) -> CustomResult { - let response: paybox::PayboxPaymentsResponse = res - .response - .parse_struct("Paybox PaymentsCaptureResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + 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 { @@ -393,11 +404,6 @@ impl ConnectorIntegration - for Paybox -{ -} - impl ConnectorIntegration for Paybox { fn get_headers( &self, @@ -414,9 +420,9 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + connectors: &settings::Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(self.base_url(connectors).to_string()) } fn get_request_body( @@ -432,7 +438,7 @@ impl ConnectorIntegration, res: Response, ) -> CustomResult, errors::ConnectorError> { - let response: paybox::RefundResponse = - res.response - .parse_struct("paybox RefundResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let response: paybox::PayboxResponse = 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 { @@ -498,9 +498,18 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(self.base_url(connectors).to_string()) + } + + fn get_request_body( + &self, + req: &types::RefundSyncRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + let connector_req = paybox::PayboxRsyncRequest::try_from(req)?; + Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } fn build_request( @@ -510,10 +519,9 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { Ok(Some( services::RequestBuilder::new() - .method(services::Method::Get) + .method(services::Method::Post) .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, )?) @@ -527,10 +535,8 @@ impl ConnectorIntegration, res: Response, ) -> CustomResult { - let response: paybox::RefundResponse = res - .response - .parse_struct("paybox RefundSyncResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + 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 { diff --git a/crates/router/src/connector/paybox/transformers.rs b/crates/router/src/connector/paybox/transformers.rs index d83c4261c1..fd9129c8a8 100644 --- a/crates/router/src/connector/paybox/transformers.rs +++ b/crates/router/src/connector/paybox/transformers.rs @@ -1,14 +1,17 @@ -use common_utils::types::MinorUnit; +use bytes::Bytes; +use common_utils::{date_time::DateFormat, errors::CustomResult, types::MinorUnit}; +use error_stack::ResultExt; +use hyperswitch_connectors::utils::CardData; +use hyperswitch_domain_models::router_data::ConnectorAuthType; use masking::Secret; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - connector::utils::PaymentsAuthorizeRequestData, + connector::utils, core::errors, types::{self, api, domain, storage::enums}, }; -//TODO: Fill the struct with respective fields pub struct PayboxRouterData { pub amount: MinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. pub router_data: T, @@ -16,7 +19,6 @@ pub struct PayboxRouterData { impl From<(MinorUnit, T)> for PayboxRouterData { fn from((amount, item): (MinorUnit, T)) -> Self { - //Todo : use utils to convert the amount to the type of amount that a connector accepts Self { amount, router_data: item, @@ -24,20 +26,294 @@ impl From<(MinorUnit, T)> for PayboxRouterData { } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, PartialEq)] +const AUTH_REQUEST: &str = "00001"; +const CAPTURE_REQUEST: &str = "00002"; +const AUTH_AND_CAPTURE_REQUEST: &str = "00003"; +const SYNC_REQUEST: &str = "00017"; +const REFUND_REQUEST: &str = "00014"; + +const SUCCESS_CODE: &str = "00000"; + +const VERSION_PAYBOX: &str = "00104"; + +const PAY_ORIGIN_INTERNET: &str = "024"; + +type Error = error_stack::Report; + +#[derive(Debug, Serialize, Eq, PartialEq)] pub struct PayboxPaymentsRequest { - amount: MinorUnit, - card: PayboxCard, + #[serde(rename = "DATEQ")] + pub date: String, + + #[serde(rename = "TYPE")] + pub transaction_type: String, + + #[serde(rename = "NUMQUESTION")] + pub paybox_request_number: String, + + #[serde(rename = "MONTANT")] + pub amount: MinorUnit, + + #[serde(rename = "REFERENCE")] + pub description_reference: String, + + #[serde(rename = "VERSION")] + pub version: String, + + #[serde(rename = "DEVISE")] + pub currency: String, + + #[serde(rename = "PORTEUR")] + pub card_number: cards::CardNumber, + + #[serde(rename = "DATEVAL")] + pub expiration_date: Secret, + + #[serde(rename = "CVV")] + pub cvv: Secret, + + #[serde(rename = "ACTIVITE")] + pub activity: String, + + #[serde(rename = "SITE")] + pub site: Secret, + + #[serde(rename = "RANG")] + pub rank: Secret, + + #[serde(rename = "CLE")] + pub key: Secret, } -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct PayboxCard { - number: cards::CardNumber, - expiry_month: Secret, - expiry_year: Secret, - cvc: Secret, - complete: bool, +#[derive(Debug, Serialize, Eq, PartialEq)] +pub struct PayboxCaptureRequest { + #[serde(rename = "DATEQ")] + pub date: String, + + #[serde(rename = "TYPE")] + pub transaction_type: String, + + #[serde(rename = "NUMQUESTION")] + pub paybox_request_number: String, + + #[serde(rename = "MONTANT")] + pub amount: MinorUnit, + + #[serde(rename = "REFERENCE")] + pub reference: String, + + #[serde(rename = "VERSION")] + pub version: String, + + #[serde(rename = "DEVISE")] + pub currency: String, + + #[serde(rename = "SITE")] + pub site: Secret, + + #[serde(rename = "RANG")] + pub rank: Secret, + + #[serde(rename = "CLE")] + pub key: Secret, + + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, +} + +impl TryFrom<&PayboxRouterData<&types::PaymentsCaptureRouterData>> for PayboxCaptureRequest { + type Error = error_stack::Report; + fn try_from( + item: &PayboxRouterData<&types::PaymentsCaptureRouterData>, + ) -> Result { + let auth_data: PayboxAuthType = + PayboxAuthType::try_from(&item.router_data.connector_auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let currency = diesel_models::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( + common_utils::date_time::now(), + DateFormat::YYYYMMDDHHmmss, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Self { + date: format_time.clone(), + transaction_type: CAPTURE_REQUEST.to_string(), + paybox_request_number: get_paybox_request_number()?, + version: VERSION_PAYBOX.to_string(), + currency, + site: auth_data.site, + rank: auth_data.rang, + key: auth_data.cle, + transaction_number: paybox_meta_data.connector_request_id, + paybox_order_id: item.router_data.request.connector_transaction_id.clone(), + amount: item.amount, + reference: item.router_data.connector_request_reference_id.to_string(), + }) + } +} + +#[derive(Debug, Serialize, Eq, PartialEq)] +pub struct PayboxRsyncRequest { + #[serde(rename = "DATEQ")] + pub date: String, + + #[serde(rename = "TYPE")] + pub transaction_type: String, + + #[serde(rename = "NUMQUESTION")] + pub paybox_request_number: String, + + #[serde(rename = "VERSION")] + pub version: String, + + #[serde(rename = "SITE")] + pub site: Secret, + + #[serde(rename = "RANG")] + pub rank: Secret, + + #[serde(rename = "CLE")] + pub key: Secret, + + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, +} + +impl TryFrom<&types::RefundSyncRouterData> for PayboxRsyncRequest { + type Error = error_stack::Report; + fn try_from(item: &types::RefundSyncRouterData) -> Result { + let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.connector_auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let format_time = common_utils::date_time::format_date( + common_utils::date_time::now(), + DateFormat::YYYYMMDDHHmmss, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Self { + date: format_time.clone(), + transaction_type: SYNC_REQUEST.to_string(), + paybox_request_number: get_paybox_request_number()?, + version: VERSION_PAYBOX.to_string(), + site: auth_data.site, + rank: auth_data.rang, + key: auth_data.cle, + transaction_number: item + .request + .connector_refund_id + .clone() + .ok_or(errors::ConnectorError::RequestEncodingFailed)?, + paybox_order_id: item.request.connector_transaction_id.clone(), + }) + } +} +#[derive(Debug, Serialize, Eq, PartialEq)] +pub struct PayboxPSyncRequest { + #[serde(rename = "DATEQ")] + pub date: String, + + #[serde(rename = "TYPE")] + pub transaction_type: String, + + #[serde(rename = "NUMQUESTION")] + pub paybox_request_number: String, + + #[serde(rename = "VERSION")] + pub version: String, + + #[serde(rename = "SITE")] + pub site: Secret, + + #[serde(rename = "RANG")] + pub rank: Secret, + + #[serde(rename = "CLE")] + pub key: Secret, + + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, +} + +impl TryFrom<&types::PaymentsSyncRouterData> for PayboxPSyncRequest { + type Error = error_stack::Report; + fn try_from(item: &types::PaymentsSyncRouterData) -> Result { + let auth_data: PayboxAuthType = PayboxAuthType::try_from(&item.connector_auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let format_time = common_utils::date_time::format_date( + common_utils::date_time::now(), + DateFormat::YYYYMMDDHHmmss, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + let paybox_meta_data: PayboxMeta = + utils::to_connector_meta(item.request.connector_meta.clone())?; + Ok(Self { + date: format_time.clone(), + transaction_type: SYNC_REQUEST.to_string(), + paybox_request_number: get_paybox_request_number()?, + version: VERSION_PAYBOX.to_string(), + site: auth_data.site, + rank: auth_data.rang, + key: auth_data.cle, + transaction_number: paybox_meta_data.connector_request_id, + paybox_order_id: item + .request + .connector_transaction_id + .get_connector_transaction_id() + .change_context(errors::ConnectorError::MissingConnectorTransactionID)?, + }) + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct PayboxMeta { + pub connector_request_id: String, +} + +#[derive(Debug, Serialize, Eq, PartialEq)] +pub struct PayboxRefundRequest { + #[serde(rename = "DATEQ")] + pub date: String, + + #[serde(rename = "TYPE")] + pub transaction_type: String, + + #[serde(rename = "NUMQUESTION")] + pub paybox_request_number: String, + + #[serde(rename = "MONTANT")] + pub amount: MinorUnit, + + #[serde(rename = "VERSION")] + pub version: String, + + #[serde(rename = "DEVISE")] + pub currency: String, + + #[serde(rename = "SITE")] + pub site: Secret, + + #[serde(rename = "RANG")] + pub rank: Secret, + + #[serde(rename = "CLE")] + pub key: Secret, + + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, } impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxPaymentsRequest { @@ -47,16 +323,37 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP ) -> Result { match item.router_data.request.payment_method_data.clone() { domain::PaymentMethodData::Card(req_card) => { - let card = PayboxCard { - 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()?, - }; + let auth_data: PayboxAuthType = + PayboxAuthType::try_from(&item.router_data.connector_auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let transaction_type = + get_transaction_type(item.router_data.request.capture_method)?; + let currency = + diesel_models::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( + common_utils::date_time::now(), + DateFormat::YYYYMMDDHHmmss, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Self { + date: format_time.clone(), + transaction_type, + paybox_request_number: get_paybox_request_number()?, amount: item.amount, - card, + description_reference: item.router_data.connector_request_reference_id.clone(), + version: VERSION_PAYBOX.to_string(), + currency, + card_number: req_card.card_number, + expiration_date, + cvv: req_card.card_cvc, + activity: PAY_ORIGIN_INTERNET.to_string(), + site: auth_data.site, + rank: auth_data.rang, + key: auth_data.cle, }) } _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), @@ -64,31 +361,59 @@ impl TryFrom<&PayboxRouterData<&types::PaymentsAuthorizeRouterData>> for PayboxP } } -//TODO: Fill the struct with respective fields -// Auth Struct -pub struct PayboxAuthType { - pub(super) api_key: Secret, +fn get_transaction_type(capture_method: Option) -> Result { + match capture_method { + Some(enums::CaptureMethod::Automatic) => Ok(AUTH_AND_CAPTURE_REQUEST.to_string()), + Some(enums::CaptureMethod::Manual) => Ok(AUTH_REQUEST.to_string()), + _ => Err(errors::ConnectorError::CaptureMethodNotSupported)?, + } +} +fn get_paybox_request_number() -> Result { + let time_stamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .ok() + .ok_or(errors::ConnectorError::RequestEncodingFailed)? + .as_millis() + .to_string(); + // unix time (in milliseconds) has 13 digits.if we consider 8 digits(the number digits to make day deterministic) there is no collision in the paybox_request_number as it will reset the paybox_request_number for each day and paybox accepting maximum length is 10 so we gonna take 9 (13-9) + let request_number = time_stamp + .get(4..) + .ok_or(errors::ConnectorError::ParsingFailed)?; + Ok(request_number.to_string()) } -impl TryFrom<&types::ConnectorAuthType> for PayboxAuthType { +#[derive(Debug, Serialize, Eq, PartialEq)] +pub struct PayboxAuthType { + pub(super) site: Secret, + pub(super) rang: Secret, + pub(super) cle: Secret, +} + +impl TryFrom<&ConnectorAuthType> for PayboxAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { - match auth_type { - types::ConnectorAuthType::HeaderKey { api_key } => Ok(Self { - api_key: api_key.to_owned(), - }), - _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), + fn try_from(auth_type: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::SignatureKey { + api_key, + key1, + api_secret, + } = auth_type + { + Ok(Self { + site: api_key.to_owned(), + rang: key1.to_owned(), + cle: api_secret.to_owned(), + }) + } else { + Err(errors::ConnectorError::FailedToObtainAuthType)? } } } -// PaymentsResponse -//TODO: Append the remaining status flags -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum PayboxPaymentStatus { Succeeded, Failed, - #[default] Processing, } @@ -102,44 +427,234 @@ impl From for enums::AttemptStatus { } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct PayboxPaymentsResponse { - status: PayboxPaymentStatus, - id: String, +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct PayboxResponse { + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, + + #[serde(rename = "CODEREPONSE")] + pub response_code: String, + + #[serde(rename = "COMMENTAIRE")] + pub response_message: String, +} + +pub fn parse_url_encoded_to_struct( + query_bytes: Bytes, +) -> CustomResult { + let (cow, _, _) = encoding_rs::ISO_8859_10.decode(&query_bytes); + serde_qs::from_str::(cow.as_ref()).change_context(errors::ConnectorError::ParsingFailed) +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum PayboxStatus { + #[serde(rename = "Remboursé")] + Refunded, + + #[serde(rename = "Annulé")] + Cancelled, + + #[serde(rename = "Autorisé")] + Authorised, + + #[serde(rename = "Capturé")] + Captured, + + #[serde(rename = "Refusé")] + Rejected, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct PayboxSyncResponse { + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, + + #[serde(rename = "CODEREPONSE")] + pub response_code: String, + + #[serde(rename = "COMMENTAIRE")] + pub response_message: String, + + #[serde(rename = "STATUS")] + pub status: PayboxStatus, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct PayboxCaptureResponse { + #[serde(rename = "NUMTRANS")] + pub transaction_number: String, + + #[serde(rename = "NUMAPPEL")] + pub paybox_order_id: String, + + #[serde(rename = "CODEREPONSE")] + pub response_code: String, + + #[serde(rename = "COMMENTAIRE")] + pub response_message: String, } impl - TryFrom> + TryFrom> for types::RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + 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, - charge_id: None, + let response = item.response.clone(); + let status = get_status_of_request(response.response_code.clone()); + match status { + true => Ok(Self { + status: enums::AttemptStatus::Pending, + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.paybox_order_id, + ), + redirection_data: None, + mandate_reference: None, + connector_metadata: Some(serde_json::json!(PayboxMeta { + connector_request_id: response.transaction_number.clone() + })), + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }), + amount_captured: None, + ..item.data }), - ..item.data - }) + false => Ok(Self { + response: Err(types::ErrorResponse { + code: response.response_code.clone(), + message: response.response_message.clone(), + reason: Some(response.response_message), + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(item.response.transaction_number), + }), + ..item.data + }), + } } } -//TODO: Fill the struct with respective fields -// REFUND : -// Type definition for RefundRequest -#[derive(Default, Debug, Serialize)] -pub struct PayboxRefundRequest { - pub amount: MinorUnit, +impl TryFrom> + for types::RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::ResponseRouterData, + ) -> Result { + let response = item.response.clone(); + let status = get_status_of_request(response.response_code.clone()); + match status { + true => Ok(Self { + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.paybox_order_id, + ), + redirection_data: None, + mandate_reference: None, + connector_metadata: Some(serde_json::json!(PayboxMeta { + connector_request_id: response.transaction_number.clone() + })), + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }), + ..item.data + }), + false => Ok(Self { + response: Err(types::ErrorResponse { + code: response.response_code.clone(), + message: response.response_message.clone(), + reason: Some(response.response_message), + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(item.response.transaction_number), + }), + ..item.data + }), + } + } +} + +impl TryFrom> + for types::RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::ResponseRouterData, + ) -> Result { + let response = item.response.clone(); + let status = get_status_of_request(response.response_code.clone()); + let connector_payment_status = item.response.status; + match status { + true => Ok(Self { + status: enums::AttemptStatus::from(connector_payment_status), + + response: Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + response.paybox_order_id, + ), + redirection_data: None, + mandate_reference: None, + connector_metadata: Some(serde_json::json!(PayboxMeta { + connector_request_id: response.transaction_number.clone() + })), + network_txn_id: None, + connector_response_reference_id: None, + incremental_authorization_allowed: None, + charge_id: None, + }), + ..item.data + }), + false => Ok(Self { + response: Err(types::ErrorResponse { + code: response.response_code.clone(), + message: response.response_message.clone(), + reason: Some(response.response_message), + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(item.response.transaction_number), + }), + ..item.data + }), + } + } +} + +impl From for common_enums::RefundStatus { + fn from(item: PayboxStatus) -> Self { + match item { + PayboxStatus::Refunded => Self::Success, + PayboxStatus::Cancelled + | PayboxStatus::Authorised + | PayboxStatus::Captured + | PayboxStatus::Rejected => Self::Failure, + } + } +} +impl From for enums::AttemptStatus { + fn from(item: PayboxStatus) -> Self { + match item { + PayboxStatus::Cancelled => Self::Voided, + PayboxStatus::Authorised => Self::Authorized, + PayboxStatus::Captured | PayboxStatus::Refunded => Self::Charged, + PayboxStatus::Rejected => Self::Failure, + } + } +} +fn get_status_of_request(item: String) -> bool { + item == *SUCCESS_CODE } impl TryFrom<&PayboxRouterData<&types::RefundsRouterData>> for PayboxRefundRequest { @@ -147,68 +662,44 @@ impl TryFrom<&PayboxRouterData<&types::RefundsRouterData>> for PayboxRefun fn try_from( item: &PayboxRouterData<&types::RefundsRouterData>, ) -> Result { + let auth_data: PayboxAuthType = + PayboxAuthType::try_from(&item.router_data.connector_auth_type) + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let currency = diesel_models::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::YYYYMMDDHHmmss, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + let paybox_meta_data: PayboxMeta = + utils::to_connector_meta(item.router_data.request.connector_metadata.clone())?; Ok(Self { - amount: item.amount.to_owned(), + date: format_time.clone(), + transaction_type: REFUND_REQUEST.to_string(), + paybox_request_number: get_paybox_request_number()?, + version: VERSION_PAYBOX.to_string(), + currency, + site: auth_data.site, + rank: auth_data.rang, + key: auth_data.cle, + transaction_number: paybox_meta_data.connector_request_id, + paybox_order_id: item.router_data.request.connector_transaction_id.clone(), + amount: item.amount, }) } } -// 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 types::RefundsRouterData -{ - type Error = error_stack::Report; - fn try_from( - item: types::RefundsResponseRouterData, - ) -> Result { - Ok(Self { - response: Ok(types::RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), - }), - ..item.data - }) - } -} - -impl TryFrom> +impl TryFrom> for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: types::RefundsResponseRouterData, ) -> Result { Ok(Self { response: Ok(types::RefundsResponseData { - connector_refund_id: item.response.id.to_string(), + connector_refund_id: item.response.transaction_number, refund_status: enums::RefundStatus::from(item.response.status), }), ..item.data @@ -216,8 +707,23 @@ impl TryFrom> } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +impl TryFrom> + for types::RefundsRouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::RefundsResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(types::RefundsResponseData { + connector_refund_id: item.response.transaction_number, + refund_status: common_enums::RefundStatus::Pending, + }), + ..item.data + }) + } +} +#[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct PayboxErrorResponse { pub status_code: u16, pub code: String, diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 89cd956c99..aca7632272 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1434,7 +1434,10 @@ impl<'a> ConnectorAuthTypeAndMetadataValidation<'a> { opennode::transformers::OpennodeAuthType::try_from(self.auth_type)?; Ok(()) } - // api_enums::Connector::Paybox => todo!(), added for future usage + api_enums::Connector::Paybox => { + paybox::transformers::PayboxAuthType::try_from(self.auth_type)?; + Ok(()) + } api_enums::Connector::Payme => { payme::transformers::PaymeAuthType::try_from(self.auth_type)?; Ok(()) diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 8b6fe7b90d..513e4fa1ee 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -420,7 +420,9 @@ impl ConnectorData { enums::Connector::Opennode => { Ok(ConnectorEnum::Old(Box::new(&connector::Opennode))) } - // enums::Connector::Paybox => Ok(ConnectorEnum::Old(Box::new(connector::Paybox::new()))), // added for future use + enums::Connector::Paybox => { + Ok(ConnectorEnum::Old(Box::new(connector::Paybox::new()))) + } // "payeezy" => Ok(ConnectorIntegrationEnum::Old(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage enums::Connector::Payme => { Ok(ConnectorEnum::Old(Box::new(connector::Payme::new()))) diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index cc8d947738..67af63b154 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -271,7 +271,7 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { api_enums::Connector::Noon => Self::Noon, api_enums::Connector::Nuvei => Self::Nuvei, api_enums::Connector::Opennode => Self::Opennode, - // api_enums::Connector::Paybox => Self::Paybox, added for future usage + api_enums::Connector::Paybox => Self::Paybox, api_enums::Connector::Payme => Self::Payme, api_enums::Connector::Payone => Self::Payone, api_enums::Connector::Paypal => Self::Paypal, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js index b8f8750a11..9318480b64 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js @@ -14,6 +14,7 @@ function normalise(input) { const exceptions = { bankofamerica: "Bank of America", cybersource: "Cybersource", + paybox: "Paybox", paypal: "Paypal", wellsfargo: "Wellsfargo", // Add more known exceptions here diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js new file mode 100644 index 0000000000..4bfeb077e4 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js @@ -0,0 +1,136 @@ +const successfulNo3DSCardDetails = { + card_number: "1111222233334444", + card_exp_month: "05", + card_exp_year: "27", + card_holder_name: "joseph Doe", + card_cvc: "222", +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + currency: "EUR", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + No3DSManualCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + No3DSAutoCapture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + Capture: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + amount_received: null, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + amount_received: null, + }, + }, + }, + Refund: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + PartialRefund: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + SyncRefund: { + Request: { + payment_method: "card", + payment_method_data: { + card: successfulNo3DSCardDetails, + }, + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + }, +}; \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Utils.js b/cypress-tests/cypress/e2e/PaymentUtils/Utils.js index 07d323d2a5..01680c47d5 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Utils.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Utils.js @@ -10,6 +10,7 @@ import { connectorDetails as datatransConnectorDetails } from "./Datatrans.js"; import { connectorDetails as iatapayConnectorDetails } from "./Iatapay.js"; import { connectorDetails as itaubankConnectorDetails } from "./ItauBank.js"; import { connectorDetails as nmiConnectorDetails } from "./Nmi.js"; +import { connectorDetails as payboxConnectorDetails } from "./Paybox.js"; import { connectorDetails as paypalConnectorDetails } from "./Paypal.js"; import { connectorDetails as stripeConnectorDetails } from "./Stripe.js"; import { connectorDetails as trustpayConnectorDetails } from "./Trustpay.js"; @@ -24,6 +25,7 @@ const connectorDetails = { iatapay: iatapayConnectorDetails, itaubank: itaubankConnectorDetails, nmi: nmiConnectorDetails, + paybox: payboxConnectorDetails, paypal: paypalConnectorDetails, stripe: stripeConnectorDetails, trustpay: trustpayConnectorDetails,