From 7bcdf45091b62b6909112fbfc9e6bea873e6a44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Thu, 2 Nov 2023 20:46:29 +0100 Subject: [PATCH 01/31] add_connector.sh inital commit --- config/config.example.toml | 2 + config/development.toml | 2 + config/docker_compose.toml | 2 + crates/api_models/src/enums.rs | 2 + crates/router/src/configs/settings.rs | 1 + crates/router/src/connector.rs | 2 + crates/router/src/connector/stancer.rs | 489 ++++++++++++++++++ .../src/connector/stancer/transformers.rs | 223 ++++++++ crates/router/src/core/payments/flows.rs | 19 + crates/router/src/types/api.rs | 1 + crates/router/tests/connectors/main.rs | 1 + .../router/tests/connectors/sample_auth.toml | 2 +- crates/router/tests/connectors/stancer.rs | 402 ++++++++++++++ crates/test_utils/src/connector_auth.rs | 3 +- loadtest/config/development.toml | 2 + scripts/add_connector.sh | 2 +- 16 files changed, 1152 insertions(+), 3 deletions(-) create mode 100644 crates/router/src/connector/stancer.rs create mode 100644 crates/router/src/connector/stancer/transformers.rs create mode 100644 crates/router/tests/connectors/stancer.rs diff --git a/config/config.example.toml b/config/config.example.toml index 59083d6c71d..7c3306012cf 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -203,6 +203,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" @@ -261,6 +262,7 @@ cards = [ "paypal", "shift4", "square", + "stancer", "stax", "stripe", "worldpay", diff --git a/config/development.toml b/config/development.toml index 5e74eafcb46..e9d71d5502f 100644 --- a/config/development.toml +++ b/config/development.toml @@ -104,6 +104,7 @@ cards = [ "prophetpay", "shift4", "square", + "stancer", "stax", "stripe", "trustpay", @@ -176,6 +177,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 20ca175ceb8..4f2da1534cf 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -118,6 +118,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" @@ -178,6 +179,7 @@ cards = [ "prophetpay", "shift4", "square", + "stancer", "stax", "stripe", "trustpay", diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index ee67c1187e6..42860107301 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -43,6 +43,7 @@ pub enum RoutingAlgorithm { #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum Connector { + Stancer, #[cfg(feature = "dummy_connector")] #[serde(rename = "phonypay")] #[strum(serialize = "phonypay")] @@ -163,6 +164,7 @@ impl Connector { #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum RoutableConnectors { + Stancer, #[cfg(feature = "dummy_connector")] #[serde(rename = "phonypay")] #[strum(serialize = "phonypay")] diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index 204060b37aa..33780e68ab1 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -568,6 +568,7 @@ pub struct Connectors { pub rapyd: ConnectorParams, pub shift4: ConnectorParams, pub square: ConnectorParams, + pub stancer: ConnectorParams, pub stax: ConnectorParams, pub stripe: ConnectorParamsWithFileUploadUrl, pub trustpay: ConnectorParamsWithMoreUrls, diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index 7849fd98a4d..3ef2f053617 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -40,6 +40,7 @@ pub mod prophetpay; pub mod rapyd; pub mod shift4; pub mod square; +pub mod stancer; pub mod stax; pub mod stripe; pub mod trustpay; @@ -64,4 +65,5 @@ pub use self::{ payu::Payu, powertranz::Powertranz, prophetpay::Prophetpay, rapyd::Rapyd, shift4::Shift4, square::Square, stax::Stax, stripe::Stripe, trustpay::Trustpay, tsys::Tsys, volt::Volt, wise::Wise, worldline::Worldline, worldpay::Worldpay, zen::Zen, +stancer::Stancer, }; diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs new file mode 100644 index 00000000000..a5c312d515c --- /dev/null +++ b/crates/router/src/connector/stancer.rs @@ -0,0 +1,489 @@ +pub mod transformers; + +use std::fmt::Debug; +use error_stack::{ResultExt, IntoReport}; +use masking::ExposeInterface; + +use crate::{ + configs::settings, + utils::{self, BytesExt}, + core::{ + errors::{self, CustomResult}, + }, + headers, services::{self, ConnectorIntegration, ConnectorValidation, request::{self, Mask}}, + types::{ + self, + api::{self, ConnectorCommon, ConnectorCommonExt}, + ErrorResponse, Response, + } +}; + + +use transformers as stancer; + +#[derive(Debug, Clone)] +pub struct Stancer; + +impl api::Payment for Stancer {} +impl api::PaymentSession for Stancer {} +impl api::ConnectorAccessToken for Stancer {} +impl api::MandateSetup for Stancer {} +impl api::PaymentAuthorize for Stancer {} +impl api::PaymentSync for Stancer {} +impl api::PaymentCapture for Stancer {} +impl api::PaymentVoid for Stancer {} +impl api::Refund for Stancer {} +impl api::RefundExecute for Stancer {} +impl api::RefundSync for Stancer {} +impl api::PaymentToken for Stancer {} + +impl + ConnectorIntegration< + api::PaymentMethodToken, + types::PaymentMethodTokenizationData, + types::PaymentsResponseData, + > for Stancer +{ + // Not Implemented (R) +} + +impl ConnectorCommonExt for Stancer +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 Stancer { + fn id(&self) -> &'static str { + "stancer" + } + + 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" + } + + fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + connectors.stancer.base_url.as_ref() + } + + fn get_auth_header(&self, auth_type:&types::ConnectorAuthType)-> CustomResult)>,errors::ConnectorError> { + let auth = stancer::StancerAuthType::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, + ) -> CustomResult { + let response: stancer::StancerErrorResponse = res + .response + .parse_struct("StancerErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + Ok(ErrorResponse { + status_code: res.status_code, + code: response.code, + message: response.message, + reason: response.reason, + }) + } +} + +impl ConnectorValidation for Stancer +{ + //TODO: implement functions when support enabled +} + +impl + ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Stancer +{ + //TODO: implement sessions flow +} + +impl ConnectorIntegration + for Stancer +{ +} + +impl + ConnectorIntegration< + api::SetupMandate, + types::SetupMandateRequestData, + types::PaymentsResponseData, + > for Stancer +{ +} + +impl + ConnectorIntegration< + api::Authorize, + types::PaymentsAuthorizeData, + types::PaymentsResponseData, + > for Stancer { + 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) -> CustomResult, errors::ConnectorError> { + let connector_router_data = + stancer::StancerRouterData::try_from(( + &self.get_currency_unit(), + req.request.currency, + req.request.amount, + req, + ))?; + let req_obj = stancer::StancerPaymentsRequest::try_from(&connector_router_data)?; + let stancer_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::::encode_to_string_of_json) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(stancer_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, + )?) + .body(types::PaymentsAuthorizeType::get_request_body(self, req)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &types::PaymentsAuthorizeRouterData, + res: Response, + ) -> CustomResult { + let response: stancer::StancerPaymentsResponse = res.response.parse_struct("Stancer PaymentsAuthorizeResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response(&self, res: Response) -> CustomResult { + self.build_error_response(res) + } +} + +impl + ConnectorIntegration + for Stancer +{ + fn get_headers( + &self, + req: &types::PaymentsSyncRouterData, + 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::PaymentsSyncRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn build_request( + &self, + req: &types::PaymentsSyncRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + services::RequestBuilder::new() + .method(services::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: &types::PaymentsSyncRouterData, + res: Response, + ) -> CustomResult { + let response: stancer:: StancerPaymentsResponse = res + .response + .parse_struct("stancer PaymentsSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { + self.build_error_response(res) + } +} + +impl + ConnectorIntegration< + api::Capture, + types::PaymentsCaptureData, + types::PaymentsResponseData, + > for Stancer +{ + fn get_headers( + &self, + req: &types::PaymentsCaptureRouterData, + 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::PaymentsCaptureRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body( + &self, + _req: &types::PaymentsCaptureRouterData, + ) -> CustomResult, errors::ConnectorError> { + Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + } + + fn build_request( + &self, + req: &types::PaymentsCaptureRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + services::RequestBuilder::new() + .method(services::Method::Post) + .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsCaptureType::get_headers( + self, req, connectors, + )?) + .body(types::PaymentsCaptureType::get_request_body(self, req)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &types::PaymentsCaptureRouterData, + res: Response, + ) -> CustomResult { + let response: stancer::StancerPaymentsResponse = res + .response + .parse_struct("Stancer PaymentsCaptureResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { + self.build_error_response(res) + } +} + +impl + ConnectorIntegration< + api::Void, + types::PaymentsCancelData, + types::PaymentsResponseData, + > for Stancer +{} + +impl + ConnectorIntegration< + api::Execute, + types::RefundsData, + types::RefundsResponseData, + > for Stancer { + fn get_headers(&self, req: &types::RefundsRouterData, 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::RefundsRouterData, _connectors: &settings::Connectors,) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn get_request_body(&self, req: &types::RefundsRouterData) -> CustomResult, errors::ConnectorError> { + let connector_router_data = + stancer::StancerRouterData::try_from(( + &self.get_currency_unit(), + req.request.currency, + req.request.refund_amount, + req, + ))?; + let req_obj = stancer::StancerRefundRequest::try_from(&connector_router_data)?; + let stancer_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::::encode_to_string_of_json) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(stancer_req)) + } + + fn build_request(&self, req: &types::RefundsRouterData, connectors: &settings::Connectors,) -> CustomResult,errors::ConnectorError> { + let request = services::RequestBuilder::new() + .method(services::Method::Post) + .url(&types::RefundExecuteType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::RefundExecuteType::get_headers(self, req, connectors)?) + .body(types::RefundExecuteType::get_request_body(self, req)?) + .build(); + Ok(Some(request)) + } + + fn handle_response( + &self, + data: &types::RefundsRouterData, + res: Response, + ) -> CustomResult,errors::ConnectorError> { + let response: stancer::RefundResponse = res.response.parse_struct("stancer RefundResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response(&self, res: Response) -> CustomResult { + self.build_error_response(res) + } +} + +impl + ConnectorIntegration for Stancer { + fn get_headers(&self, req: &types::RefundSyncRouterData,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::RefundSyncRouterData,_connectors: &settings::Connectors,) -> CustomResult { + Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + } + + fn build_request( + &self, + req: &types::RefundSyncRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + services::RequestBuilder::new() + .method(services::Method::Get) + .url(&types::RefundSyncType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .body(types::RefundSyncType::get_request_body(self, req)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &types::RefundSyncRouterData, + res: Response, + ) -> CustomResult { + let response: stancer::RefundResponse = res.response.parse_struct("stancer RefundSyncResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response(&self, res: Response) -> CustomResult { + self.build_error_response(res) + } +} + +#[async_trait::async_trait] +impl api::IncomingWebhook for Stancer { + fn get_webhook_object_reference_id( + &self, + _request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(errors::ConnectorError::WebhooksNotImplemented).into_report() + } + + fn get_webhook_event_type( + &self, + _request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(errors::ConnectorError::WebhooksNotImplemented).into_report() + } + + fn get_webhook_resource_object( + &self, + _request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(errors::ConnectorError::WebhooksNotImplemented).into_report() + } +} diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs new file mode 100644 index 00000000000..1ed208e84dc --- /dev/null +++ b/crates/router/src/connector/stancer/transformers.rs @@ -0,0 +1,223 @@ +use serde::{Deserialize, Serialize}; +use masking::Secret; +use crate::{connector::utils::{PaymentsAuthorizeRequestData},core::errors,types::{self,api, storage::enums}}; + +//TODO: Fill the struct with respective fields +pub struct StancerRouterData { + 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 StancerRouterData +{ + 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 StancerPaymentsRequest { + amount: i64, + card: StancerCard +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct StancerCard { + name: Secret, + number: cards::CardNumber, + expiry_month: Secret, + expiry_year: Secret, + cvc: Secret, + complete: bool, +} + +impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for StancerPaymentsRequest { + type Error = error_stack::Report; + fn try_from(item: &StancerRouterData<&types::PaymentsAuthorizeRouterData>) -> Result { + match item.router_data.request.payment_method_data.clone() { + api::PaymentMethodData::Card(req_card) => { + let card = StancerCard { + name: req_card.card_holder_name, + 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 StancerAuthType { + pub(super) api_key: Secret +} + +impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { + 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()), + } + } +} +// PaymentsResponse +//TODO: Append the remaining status flags +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum StancerPaymentStatus { + Succeeded, + Failed, + #[default] + Processing, +} + +impl From for enums::AttemptStatus { + fn from(item: StancerPaymentStatus) -> Self { + match item { + StancerPaymentStatus::Succeeded => Self::Charged, + StancerPaymentStatus::Failed => Self::Failure, + StancerPaymentStatus::Processing => Self::Authorizing, + } + } +} + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct StancerPaymentsResponse { + status: StancerPaymentStatus, + 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, + }), + ..item.data + }) + } +} + +//TODO: Fill the struct with respective fields +// REFUND : +// Type definition for RefundRequest +#[derive(Default, Debug, Serialize)] +pub struct StancerRefundRequest { + pub amount: i64 +} + +impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRefundRequest { + type Error = error_stack::Report; + fn try_from(item: &StancerRouterData<&types::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 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> 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 + }) + } + } + +//TODO: Fill the struct with respective fields +#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct StancerErrorResponse { + pub status_code: u16, + pub code: String, + pub message: String, + pub reason: Option, +} diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index c55df8e35d6..93a319fe81f 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -142,6 +142,7 @@ impl } default_imp_for_complete_authorize!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Bitpay, @@ -207,6 +208,7 @@ impl { } default_imp_for_webhook_source_verification!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -285,6 +287,7 @@ impl } default_imp_for_create_customer!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -363,6 +366,7 @@ impl services::ConnectorRedirectResponse for connector::DummyConnec } default_imp_for_connector_redirect_response!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Bitpay, @@ -411,6 +415,7 @@ macro_rules! default_imp_for_connector_request_id { impl api::ConnectorTransactionId for connector::DummyConnector {} default_imp_for_connector_request_id!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -491,6 +496,7 @@ impl } default_imp_for_accept_dispute!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -591,6 +597,7 @@ impl } default_imp_for_file_upload!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -668,6 +675,7 @@ impl } default_imp_for_submit_evidence!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -745,6 +753,7 @@ impl } default_imp_for_defend_dispute!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -823,6 +832,7 @@ impl } default_imp_for_pre_processing_steps!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -882,6 +892,7 @@ macro_rules! default_imp_for_payouts { impl api::Payouts for connector::DummyConnector {} default_imp_for_payouts!( + connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -960,6 +971,7 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_create!( + connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1041,6 +1053,7 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_eligibility!( + connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1119,6 +1132,7 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_fulfill!( + connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1197,6 +1211,7 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_cancel!( + connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1275,6 +1290,7 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_quote!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1354,6 +1370,7 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_recipient!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1432,6 +1449,7 @@ impl } default_imp_for_approve!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1511,6 +1529,7 @@ impl } default_imp_for_reject!( + connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 8f5a0f8a59f..50b84907763 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -352,6 +352,7 @@ impl ConnectorData { enums::Connector::Rapyd => Ok(Box::new(&connector::Rapyd)), enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), enums::Connector::Square => Ok(Box::new(&connector::Square)), + enums::Connector::Stancer => Ok(Box::new(&connector::Stancer)), enums::Connector::Stax => Ok(Box::new(&connector::Stax)), enums::Connector::Stripe => Ok(Box::new(&connector::Stripe)), enums::Connector::Wise => Ok(Box::new(&connector::Wise)), diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs index ed06312b77a..a337e0d2a67 100644 --- a/crates/router/tests/connectors/main.rs +++ b/crates/router/tests/connectors/main.rs @@ -50,6 +50,7 @@ mod stax; mod stripe; mod trustpay; mod tsys; +mod stancer; mod utils; mod volt; mod wise; diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index 0966db95a42..05b74ea3466 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -183,4 +183,4 @@ api_key="API Key" api_key="API Key" [prophetpay] -api_key="API Key" \ No newline at end of file +api_key="API Key"\n\n[stancer]\napi_key="API Key" diff --git a/crates/router/tests/connectors/stancer.rs b/crates/router/tests/connectors/stancer.rs new file mode 100644 index 00000000000..8aabaa075a7 --- /dev/null +++ b/crates/router/tests/connectors/stancer.rs @@ -0,0 +1,402 @@ +use masking::Secret; +use router::{ + core::utils as core_utils, + types::{self, api, storage::enums, +}}; + +use crate::utils::{self, ConnectorActions}; +use test_utils::connector_auth; + +#[derive(Clone, Copy)] +struct StancerTest; +impl ConnectorActions for StancerTest {} +impl utils::Connector for StancerTest { + fn get_data(&self) -> types::api::ConnectorData { + use router::connector::Stancer; + types::api::ConnectorData { + connector: Box::new(&Stancer), + connector_name: types::Connector::Stancer, + get_token: types::api::GetToken::Connector, + } + } + + fn get_auth_token(&self) -> types::ConnectorAuthType { + utils::to_connector_auth_type( + connector_auth::ConnectorAuthentication::new() + .stancer + .expect("Missing connector authentication configuration").into(), + ) + } + + fn get_name(&self) -> String { + "stancer".to_string() + } +} + +static CONNECTOR: StancerTest = StancerTest {}; + +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: router::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: router::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 scenerios +// 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: types::api::PaymentMethodData::Card(api::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: types::api::PaymentMethodData::Card(api::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: types::api::PaymentMethodData::Card(api::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 d774e2530e9..8aaee3f41e1 100644 --- a/crates/test_utils/src/connector_auth.rs +++ b/crates/test_utils/src/connector_auth.rs @@ -51,7 +51,8 @@ pub struct ConnectorAuthentication { pub prophetpay: Option, pub rapyd: Option, pub shift4: Option, - pub square: Option, + pub square: Option, + pub stancer: Option, pub stax: Option, pub stripe: Option, pub stripe_au: Option, diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index 7cdbc8dd6fd..05b041c2f80 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -104,6 +104,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" @@ -163,6 +164,7 @@ cards = [ "prophetpay", "shift4", "square", + "stancer", "stax", "stripe", "trustpay", diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh index bcd02f6cbd6..9f12fdd46df 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 bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource dlocal dummyconnector fiserv forte globalpay globepay gocardless helcim iatapay klarna mollie multisafepay nexinets noon nuvei opayo opennode payeezy payme paypal payu powertranz prophetpay rapyd shift4 square stax stripe trustpay tsys volt wise worldline worldpay "$1") + connectors=(aci adyen airwallex applepay authorizedotnet bambora bitpay bluesnap boku braintree cashtocode checkout coinbase cryptopay cybersource dlocal dummyconnector fiserv forte globalpay globepay gocardless helcim iatapay klarna mollie multisafepay nexinets noon nuvei opayo opennode payeezy payme paypal payu powertranz prophetpay rapyd shift4 square stancer stax stripe trustpay tsys volt wise worldline worldpay "$1") IFS=$'\n' sorted=($(sort <<<"${connectors[*]}")); unset IFS res=`echo ${sorted[@]}` sed -i'' -e "s/^ connectors=.*/ connectors=($res \"\$1\")/" $self.tmp From 3968eb622adbb1b015941e90d1609b308b0982f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Thu, 2 Nov 2023 20:48:37 +0100 Subject: [PATCH 02/31] Stancer API handles amount in lower unit (cents) --- crates/router/src/connector/stancer.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index a5c312d515c..34f60458f06 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -71,10 +71,7 @@ impl ConnectorCommon for Stancer { } 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 + api::CurrencyUnit::Minor } fn common_get_content_type(&self) -> &'static str { From 13e78e4cc37aa6ec14ca8a9d82f6a0eae0c47575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Thu, 2 Nov 2023 21:08:22 +0100 Subject: [PATCH 03/31] Enable capture methods as automatic, manual, manual multiple --- crates/router/src/connector/stancer.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 34f60458f06..839c040b442 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -106,9 +106,21 @@ impl ConnectorCommon for Stancer { } } -impl ConnectorValidation for Stancer -{ - //TODO: implement functions when support enabled +impl ConnectorValidation for Stancer { + fn validate_capture_method( + &self, + capture_method: Option, + ) -> CustomResult<(), errors::ConnectorError> { + let capture_method = capture_method.unwrap_or_default(); + match capture_method { + enums::CaptureMethod::Automatic + | enums::CaptureMethod::Manual + | enums::CaptureMethod::ManualMultiple => Ok(()), + enums::CaptureMethod::Scheduled => Err( + connector_utils::construct_not_implemented_error_report(capture_method, self.id()), + ), + } + } } impl From 8cc578b68737f184423c50e8ba7712ea44c8bcd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Thu, 2 Nov 2023 22:07:40 +0100 Subject: [PATCH 04/31] Bearer token API auth --- crates/router/src/connector/stancer.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 839c040b442..322984a908e 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -82,10 +82,16 @@ impl ConnectorCommon for Stancer { connectors.stancer.base_url.as_ref() } - fn get_auth_header(&self, auth_type:&types::ConnectorAuthType)-> CustomResult)>,errors::ConnectorError> { - let auth = stancer::StancerAuthType::try_from(auth_type) + fn get_auth_header( + &self, + auth_type: &types::ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { + let auth = stancer::StancerAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - Ok(vec![(headers::AUTHORIZATION.to_string(), auth.api_key.expose().into_masked())]) + Ok(vec![( + headers::AUTHORIZATION.to_string(), + format!("Bearer {}", auth.api_key.expose()).into_masked(), + )]) } fn build_error_response( From ed3cedaa2651bc8ea42a0b107d2e530b6f8e8fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Thu, 2 Nov 2023 23:01:15 +0100 Subject: [PATCH 05/31] Fill Stancer structs --- crates/router/src/connector/stancer.rs | 2 +- .../src/connector/stancer/transformers.rs | 125 +++++++++++++----- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 322984a908e..53b450a65c2 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -136,7 +136,7 @@ impl types::PaymentsResponseData, > for Stancer { - //TODO: implement sessions flow + // Not Implemented (R) } impl ConnectorIntegration diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 1ed208e84dc..2712e788726 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -2,9 +2,8 @@ use serde::{Deserialize, Serialize}; use masking::Secret; use crate::{connector::utils::{PaymentsAuthorizeRequestData},core::errors,types::{self,api, storage::enums}}; -//TODO: Fill the struct with respective fields pub struct StancerRouterData { - pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub amount: i32, pub router_data: T, } @@ -12,7 +11,7 @@ impl TryFrom<( &types::api::CurrencyUnit, types::storage::enums::Currency, - i64, + i32, T, )> for StancerRouterData { @@ -21,11 +20,10 @@ impl (_currency_unit, _currency, amount, item): ( &types::api::CurrencyUnit, types::storage::enums::Currency, - i64, + i32, T, ), ) -> Result { - //Todo : use utils to convert the amount to the type of amount that a connector accepts Ok(Self { amount, router_data: item, @@ -33,21 +31,57 @@ impl } } -//TODO: Fill the struct with respective fields #[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct StancerPaymentsRequest { - amount: i64, - card: StancerCard + amount: i32, + currency: String, + auth: Option, + card: Option, + sepa: Option>StancerSepa>, + customer: Option, + capture: Option, + description: Option, + order_id: Option, + unique_id: Option, + return_url: Option, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct StancerAuth { + return_url: Option, + device: Option>, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct StancerCard { name: Secret, number: cards::CardNumber, - expiry_month: Secret, - expiry_year: Secret, + exp_month: Secret, + exp_year: Secret, cvc: Secret, - complete: bool, + external_id: Option, + zip_code: Option, + customer: Option, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct StancerSepa { + name: Secret, + bic: Option, + iban: cards::CardNumber, + mandate: String, + date_mandate: String, + customer: Option, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct StancerCustomer { + email: Option, + name: Option, + mobile: Option, + date_birth: Option, + legal_id: Option, + external_id: Option, } impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for StancerPaymentsRequest { @@ -73,10 +107,10 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Stance } } -//TODO: Fill the struct with respective fields // Auth Struct pub struct StancerAuthType { pub(super) api_key: Secret + pub(super) api_secret: Secret, } impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { @@ -90,32 +124,58 @@ impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { } } } + // PaymentsResponse -//TODO: Append the remaining status flags #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum StancerPaymentStatus { - Succeeded, + Refused, + Canceled, + Authorized, + Capture_Sent, + Captured, + Disputed, Failed, + Expired, #[default] - Processing, + To_Capture, } impl From for enums::AttemptStatus { fn from(item: StancerPaymentStatus) -> Self { match item { - StancerPaymentStatus::Succeeded => Self::Charged, StancerPaymentStatus::Failed => Self::Failure, - StancerPaymentStatus::Processing => Self::Authorizing, + StancerPaymentStatus::Refused => Self::Failure, + StancerPaymentStatus::Expired => Self::Failure, + StancerPaymentStatus::Canceled => Self::Failure, + StancerPaymentStatus::Disputed => Self::Failure, + StancerPaymentStatus::Authorized => Self::Authorizing, + StancerPaymentStatus::To_Capture => Self::Authorizing, + StancerPaymentStatus::Capture_Sent => Self::Charged, + StancerPaymentStatus::Captured => Self::Charged, } } } -//TODO: Fill the struct with respective fields #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct StancerPaymentsResponse { - status: StancerPaymentStatus, id: String, + status: StancerPaymentStatus, + response: String, + amount: i32, + currency: String, + auth: Option, + card: Option, + sepa: Option>StancerSepa>, + customer: Option, + capture: Option, + description: Option, + order_id: Option, + unique_id: Option, + date_trans: i32, + date_bank: Option, + return_url: Option, + created: i32, } impl TryFrom> for types::RouterData { @@ -136,12 +196,12 @@ impl TryFromi32, + pub payment: String, } impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRefundRequest { @@ -154,32 +214,39 @@ impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRef } // Type definition for Refund Response - #[allow(dead_code)] #[derive(Debug, Serialize, Default, Deserialize, Clone)] pub enum RefundStatus { - Succeeded, Failed, + Not_Honored, + Refund_Sent, + Refunded, #[default] - Processing, + To_Refund, } 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 + RefundStatus::Not_Honored => Self::Failure, + RefundStatus::To_Refund => Self::Pending, + RefundStatus::Refund_Sent => Self::Pending, + RefundStatus::Succeeded => Self::Success, } } } -//TODO: Fill the struct with respective fields #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct RefundResponse { id: String, status: RefundStatus + amount: i32, + currency: String, + date_bank: i32, + date_refund: i32, + payment: String, + created: i32, } impl TryFrom> @@ -213,11 +280,9 @@ impl TryFrom> for t } } -//TODO: Fill the struct with respective fields #[derive(Default, Debug, Serialize, Deserialize, PartialEq)] pub struct StancerErrorResponse { pub status_code: u16, pub code: String, pub message: String, - pub reason: Option, } From 9d0e6405e53cc2234340b0408626aecb2161fe3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Mon, 20 Nov 2023 13:40:15 +0100 Subject: [PATCH 06/31] maintain alphabetical order --- config/config.example.toml | 2 +- config/development.toml | 2 +- config/docker_compose.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 7c3306012cf..5bbb3e8a2c6 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -203,8 +203,8 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" stripe.base_url_file_upload = "https://files.stripe.com/" diff --git a/config/development.toml b/config/development.toml index e9d71d5502f..4cf7c1c3c4e 100644 --- a/config/development.toml +++ b/config/development.toml @@ -177,8 +177,8 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" stripe.base_url_file_upload = "https://files.stripe.com/" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 4f2da1534cf..fe133123aef 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -118,8 +118,8 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" stripe.base_url_file_upload = "https://files.stripe.com/" From 72e8bc84d91c8123615f9758d3adbbea2f175a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Mon, 20 Nov 2023 13:41:11 +0100 Subject: [PATCH 07/31] fix issie from add_connector.sh --- crates/router/tests/connectors/sample_auth.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index 05b74ea3466..ae45e25243d 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -183,4 +183,7 @@ api_key="API Key" api_key="API Key" [prophetpay] -api_key="API Key"\n\n[stancer]\napi_key="API Key" +api_key="API Key" + +[stancer] +api_key="API Key" From 258c64c7a14a5169fb9ea8a339207cc0d494ef0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Mon, 20 Nov 2023 13:41:31 +0100 Subject: [PATCH 08/31] maintain alphabetical order --- crates/api_models/src/enums.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 42860107301..1ab32df672d 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -43,7 +43,6 @@ pub enum RoutingAlgorithm { #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum Connector { - Stancer, #[cfg(feature = "dummy_connector")] #[serde(rename = "phonypay")] #[strum(serialize = "phonypay")] @@ -112,6 +111,7 @@ pub enum Connector { Rapyd, Shift4, Square, + Stancer, Stax, Stripe, Trustpay, @@ -164,7 +164,6 @@ impl Connector { #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum RoutableConnectors { - Stancer, #[cfg(feature = "dummy_connector")] #[serde(rename = "phonypay")] #[strum(serialize = "phonypay")] @@ -233,6 +232,7 @@ pub enum RoutableConnectors { Rapyd, Shift4, Square, + Stancer, Stax, Stripe, Trustpay, From 08c1f3ef08e5f7d0956e05397202c44d7420bcff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Mon, 20 Nov 2023 13:41:50 +0100 Subject: [PATCH 09/31] maintain alphabetical order --- crates/test_utils/src/connector_auth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/test_utils/src/connector_auth.rs b/crates/test_utils/src/connector_auth.rs index 8aaee3f41e1..b8f3cffd9d5 100644 --- a/crates/test_utils/src/connector_auth.rs +++ b/crates/test_utils/src/connector_auth.rs @@ -51,8 +51,8 @@ pub struct ConnectorAuthentication { pub prophetpay: Option, pub rapyd: Option, pub shift4: Option, - pub square: Option, - pub stancer: Option, + pub square: Option, + pub stancer: Option, pub stax: Option, pub stripe: Option, pub stripe_au: Option, From 748eb2a22e2943ec1a9e2cae5e06a2ddb2057292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Mon, 20 Nov 2023 13:42:32 +0100 Subject: [PATCH 10/31] fix typos --- .../router/src/connector/stancer/transformers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 2712e788726..7320233239b 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -37,7 +37,7 @@ pub struct StancerPaymentsRequest { currency: String, auth: Option, card: Option, - sepa: Option>StancerSepa>, + sepa: Option, customer: Option, capture: Option, description: Option, @@ -110,7 +110,6 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Stance // Auth Struct pub struct StancerAuthType { pub(super) api_key: Secret - pub(super) api_secret: Secret, } impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { @@ -216,22 +215,23 @@ impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRef // Type definition for Refund Response #[allow(dead_code)] #[derive(Debug, Serialize, Default, Deserialize, Clone)] +#[serde(rename_all = 'snake_case'] pub enum RefundStatus { Failed, - Not_Honored, - Refund_Sent, + NotHonored, + RefundSent, Refunded, #[default] - To_Refund, + ToRefund, } impl From for enums::RefundStatus { fn from(item: RefundStatus) -> Self { match item { RefundStatus::Failed => Self::Failure, - RefundStatus::Not_Honored => Self::Failure, - RefundStatus::To_Refund => Self::Pending, - RefundStatus::Refund_Sent => Self::Pending, + RefundStatus::NotHonored => Self::Failure, + RefundStatus::ToRefund => Self::Pending, + RefundStatus::RefundSent => Self::Pending, RefundStatus::Succeeded => Self::Success, } } From 0c3f9deb91e3dc6c7d7cf62ec8443e76f99b57d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Beaujean?= Date: Mon, 20 Nov 2023 13:49:36 +0100 Subject: [PATCH 11/31] useless use of snake_case --- crates/router/src/connector/stancer/transformers.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 7320233239b..d92a1454669 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -215,7 +215,6 @@ impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRef // Type definition for Refund Response #[allow(dead_code)] #[derive(Debug, Serialize, Default, Deserialize, Clone)] -#[serde(rename_all = 'snake_case'] pub enum RefundStatus { Failed, NotHonored, From 1dfed336ba653616a9d62d816d85562b2368adbb Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Thu, 23 Nov 2023 21:59:06 -0500 Subject: [PATCH 12/31] add connector `stancer` with `add_connector` script + fix compilation issues --- config/config.example.toml | 1 + config/development.toml | 1 + config/docker_compose.toml | 1 + crates/api_models/src/routing.rs | 1 + crates/euclid/src/enums.rs | 1 + crates/router/src/configs/settings.rs | 2 +- crates/router/src/connector/stancer.rs | 254 ++++++++++-------- .../src/connector/stancer/transformers.rs | 171 +++++------- crates/router/src/core/admin.rs | 4 + crates/router/src/core/payments/flows.rs | 38 +-- .../src/core/payments/routing/transformers.rs | 1 + crates/router/src/types/api.rs | 2 +- crates/router/src/types/transformers.rs | 2 + crates/router/tests/connectors/main.rs | 2 +- crates/router/tests/connectors/stancer.rs | 39 ++- loadtest/config/development.toml | 2 +- 16 files changed, 276 insertions(+), 246 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 11d7d9d589e..9dbe3d9053c 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -206,6 +206,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stancer.base_url = "https://api.stancer.com" stax.base_url = "https://apiprod.fattlabs.com/" diff --git a/config/development.toml b/config/development.toml index e629d8eda7c..6342d162fca 100644 --- a/config/development.toml +++ b/config/development.toml @@ -181,6 +181,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stancer.base_url = "https://api.stancer.com" stax.base_url = "https://apiprod.fattlabs.com/" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index f048babd531..eaf797e8b63 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -121,6 +121,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" +stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stancer.base_url = "https://api.stancer.com" stax.base_url = "https://apiprod.fattlabs.com/" diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 47a44ea7443..1b6aaebfa79 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -341,6 +341,7 @@ impl From for ast::ConnectorChoice { RoutableConnectors::Rapyd => euclid_enums::Connector::Rapyd, RoutableConnectors::Shift4 => euclid_enums::Connector::Shift4, RoutableConnectors::Square => euclid_enums::Connector::Square, + RoutableConnectors::Stancer => euclid_enums::Connector::Stancer, RoutableConnectors::Stax => euclid_enums::Connector::Stax, RoutableConnectors::Stripe => euclid_enums::Connector::Stripe, RoutableConnectors::Trustpay => euclid_enums::Connector::Trustpay, diff --git a/crates/euclid/src/enums.rs b/crates/euclid/src/enums.rs index dc6d9f66a58..a4a759b5284 100644 --- a/crates/euclid/src/enums.rs +++ b/crates/euclid/src/enums.rs @@ -121,6 +121,7 @@ pub enum Connector { Rapyd, Shift4, Square, + Stancer, Stax, Stripe, Trustpay, diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index 95859e5845c..eb1531b76fa 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -575,7 +575,7 @@ pub struct Connectors { pub rapyd: ConnectorParams, pub shift4: ConnectorParams, pub square: ConnectorParams, - pub stancer: ConnectorParams, + pub stancer: ConnectorParams, pub stax: ConnectorParams, pub stripe: ConnectorParamsWithFileUploadUrl, pub trustpay: ConnectorParamsWithMoreUrls, diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 53b450a65c2..f588d058d62 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -1,26 +1,28 @@ pub mod transformers; use std::fmt::Debug; -use error_stack::{ResultExt, IntoReport}; + +use error_stack::{IntoReport, ResultExt}; use masking::ExposeInterface; +use transformers as stancer; use crate::{ configs::settings, - utils::{self, BytesExt}, - core::{ - errors::{self, CustomResult}, + core::errors::{self, CustomResult}, + headers, + services::{ + self, + request::{self, Mask}, + ConnectorIntegration, ConnectorValidation, }, - headers, services::{self, ConnectorIntegration, ConnectorValidation, request::{self, Mask}}, types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, ErrorResponse, Response, - } + }, + utils::{self, BytesExt}, }; - -use transformers as stancer; - #[derive(Debug, Clone)] pub struct Stancer; @@ -49,7 +51,8 @@ impl impl ConnectorCommonExt for Stancer where - Self: ConnectorIntegration,{ + Self: ConnectorIntegration, +{ fn build_headers( &self, req: &types::RouterData, @@ -71,7 +74,10 @@ impl ConnectorCommon for Stancer { } fn get_currency_unit(&self) -> api::CurrencyUnit { - api::CurrencyUnit::Minor + 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 { @@ -90,7 +96,7 @@ impl ConnectorCommon for Stancer { .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( headers::AUTHORIZATION.to_string(), - format!("Bearer {}", auth.api_key.expose()).into_masked(), + auth.api_key.expose().into_masked(), )]) } @@ -108,35 +114,19 @@ impl ConnectorCommon for Stancer { code: response.code, message: response.message, reason: response.reason, + attempt_status: None, }) } } impl ConnectorValidation for Stancer { - fn validate_capture_method( - &self, - capture_method: Option, - ) -> CustomResult<(), errors::ConnectorError> { - let capture_method = capture_method.unwrap_or_default(); - match capture_method { - enums::CaptureMethod::Automatic - | enums::CaptureMethod::Manual - | enums::CaptureMethod::ManualMultiple => Ok(()), - enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_implemented_error_report(capture_method, self.id()), - ), - } - } + //TODO: implement functions when support enabled } -impl - ConnectorIntegration< - api::Session, - types::PaymentsSessionData, - types::PaymentsResponseData, - > for Stancer +impl ConnectorIntegration + for Stancer { - // Not Implemented (R) + //TODO: implement sessions flow } impl ConnectorIntegration @@ -153,13 +143,14 @@ impl { } -impl - ConnectorIntegration< - api::Authorize, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - > for Stancer { - fn get_headers(&self, req: &types::PaymentsAuthorizeRouterData, connectors: &settings::Connectors,) -> CustomResult)>,errors::ConnectorError> { +impl ConnectorIntegration + for Stancer +{ + fn get_headers( + &self, + req: &types::PaymentsAuthorizeRouterData, + connectors: &settings::Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -167,21 +158,31 @@ impl self.common_get_content_type() } - fn get_url(&self, _req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors,) -> CustomResult { + 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) -> CustomResult, errors::ConnectorError> { - let connector_router_data = - stancer::StancerRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount, - req, - ))?; + fn get_request_body( + &self, + req: &types::PaymentsAuthorizeRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + let connector_router_data = stancer::StancerRouterData::try_from(( + &self.get_currency_unit(), + req.request.currency, + req.request.amount, + req, + ))?; let req_obj = stancer::StancerPaymentsRequest::try_from(&connector_router_data)?; - let stancer_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::::encode_to_string_of_json) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + let stancer_req = types::RequestBody::log_and_get_request_body( + &req_obj, + utils::Encode::::encode_to_string_of_json, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(stancer_req)) } @@ -200,7 +201,9 @@ impl .headers(types::PaymentsAuthorizeType::get_headers( self, req, connectors, )?) - .body(types::PaymentsAuthorizeType::get_request_body(self, req)?) + .body(types::PaymentsAuthorizeType::get_request_body( + self, req, connectors, + )?) .build(), )) } @@ -209,8 +212,11 @@ impl &self, data: &types::PaymentsAuthorizeRouterData, res: Response, - ) -> CustomResult { - let response: stancer::StancerPaymentsResponse = res.response.parse_struct("Stancer PaymentsAuthorizeResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + ) -> CustomResult { + let response: stancer::StancerPaymentsResponse = res + .response + .parse_struct("Stancer PaymentsAuthorizeResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, data: data.clone(), @@ -218,13 +224,15 @@ impl }) } - fn get_error_response(&self, res: Response) -> CustomResult { + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { self.build_error_response(res) } } -impl - ConnectorIntegration +impl ConnectorIntegration for Stancer { fn get_headers( @@ -267,7 +275,7 @@ impl data: &types::PaymentsSyncRouterData, res: Response, ) -> CustomResult { - let response: stancer:: StancerPaymentsResponse = res + let response: stancer::StancerPaymentsResponse = res .response .parse_struct("stancer PaymentsSyncResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; @@ -286,12 +294,8 @@ impl } } -impl - ConnectorIntegration< - api::Capture, - types::PaymentsCaptureData, - types::PaymentsResponseData, - > for Stancer +impl ConnectorIntegration + for Stancer { fn get_headers( &self, @@ -316,6 +320,7 @@ impl fn get_request_body( &self, _req: &types::PaymentsCaptureRouterData, + _connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) } @@ -333,7 +338,9 @@ impl .headers(types::PaymentsCaptureType::get_headers( self, req, connectors, )?) - .body(types::PaymentsCaptureType::get_request_body(self, req)?) + .body(types::PaymentsCaptureType::get_request_body( + self, req, connectors, + )?) .build(), )) } @@ -362,21 +369,19 @@ impl } } -impl - ConnectorIntegration< - api::Void, - types::PaymentsCancelData, - types::PaymentsResponseData, - > for Stancer -{} +impl ConnectorIntegration + for Stancer +{ +} -impl - ConnectorIntegration< - api::Execute, - types::RefundsData, - types::RefundsResponseData, - > for Stancer { - fn get_headers(&self, req: &types::RefundsRouterData, connectors: &settings::Connectors,) -> CustomResult)>,errors::ConnectorError> { +impl ConnectorIntegration + for Stancer +{ + fn get_headers( + &self, + req: &types::RefundsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -384,31 +389,49 @@ impl self.common_get_content_type() } - fn get_url(&self, _req: &types::RefundsRouterData, _connectors: &settings::Connectors,) -> CustomResult { + fn get_url( + &self, + _req: &types::RefundsRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) } - fn get_request_body(&self, req: &types::RefundsRouterData) -> CustomResult, errors::ConnectorError> { - let connector_router_data = - stancer::StancerRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.refund_amount, - req, - ))?; + fn get_request_body( + &self, + req: &types::RefundsRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + let connector_router_data = stancer::StancerRouterData::try_from(( + &self.get_currency_unit(), + req.request.currency, + req.request.refund_amount, + req, + ))?; let req_obj = stancer::StancerRefundRequest::try_from(&connector_router_data)?; - let stancer_req = types::RequestBody::log_and_get_request_body(&req_obj, utils::Encode::::encode_to_string_of_json) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + let stancer_req = types::RequestBody::log_and_get_request_body( + &req_obj, + utils::Encode::::encode_to_string_of_json, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(stancer_req)) } - fn build_request(&self, req: &types::RefundsRouterData, connectors: &settings::Connectors,) -> CustomResult,errors::ConnectorError> { + fn build_request( + &self, + req: &types::RefundsRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { let request = services::RequestBuilder::new() .method(services::Method::Post) .url(&types::RefundExecuteType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundExecuteType::get_headers(self, req, connectors)?) - .body(types::RefundExecuteType::get_request_body(self, req)?) + .headers(types::RefundExecuteType::get_headers( + self, req, connectors, + )?) + .body(types::RefundExecuteType::get_request_body( + self, req, connectors, + )?) .build(); Ok(Some(request)) } @@ -417,8 +440,11 @@ impl &self, data: &types::RefundsRouterData, res: Response, - ) -> CustomResult,errors::ConnectorError> { - let response: stancer::RefundResponse = res.response.parse_struct("stancer RefundResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + ) -> CustomResult, errors::ConnectorError> { + let response: stancer::RefundResponse = res + .response + .parse_struct("stancer RefundResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, data: data.clone(), @@ -426,14 +452,20 @@ impl }) } - fn get_error_response(&self, res: Response) -> CustomResult { + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { self.build_error_response(res) } } -impl - ConnectorIntegration for Stancer { - fn get_headers(&self, req: &types::RefundSyncRouterData,connectors: &settings::Connectors,) -> CustomResult)>,errors::ConnectorError> { +impl ConnectorIntegration for Stancer { + fn get_headers( + &self, + req: &types::RefundSyncRouterData, + connectors: &settings::Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -441,7 +473,11 @@ impl self.common_get_content_type() } - fn get_url(&self, _req: &types::RefundSyncRouterData,_connectors: &settings::Connectors,) -> CustomResult { + fn get_url( + &self, + _req: &types::RefundSyncRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) } @@ -456,7 +492,9 @@ impl .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundSyncType::get_headers(self, req, connectors)?) - .body(types::RefundSyncType::get_request_body(self, req)?) + .body(types::RefundSyncType::get_request_body( + self, req, connectors, + )?) .build(), )) } @@ -465,8 +503,11 @@ impl &self, data: &types::RefundSyncRouterData, res: Response, - ) -> CustomResult { - let response: stancer::RefundResponse = res.response.parse_struct("stancer RefundSyncResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + ) -> CustomResult { + let response: stancer::RefundResponse = res + .response + .parse_struct("stancer RefundSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, data: data.clone(), @@ -474,7 +515,10 @@ impl }) } - fn get_error_response(&self, res: Response) -> CustomResult { + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { self.build_error_response(res) } } @@ -498,7 +542,7 @@ impl api::IncomingWebhook for Stancer { fn get_webhook_resource_object( &self, _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } } diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index d92a1454669..e0c4f58c890 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -1,9 +1,15 @@ -use serde::{Deserialize, Serialize}; use masking::Secret; -use crate::{connector::utils::{PaymentsAuthorizeRequestData},core::errors,types::{self,api, storage::enums}}; +use serde::{Deserialize, Serialize}; +use crate::{ + connector::utils::PaymentsAuthorizeRequestData, + core::errors, + types::{self, api, storage::enums}, +}; + +//TODO: Fill the struct with respective fields pub struct StancerRouterData { - pub amount: i32, + pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc. pub router_data: T, } @@ -11,7 +17,7 @@ impl TryFrom<( &types::api::CurrencyUnit, types::storage::enums::Currency, - i32, + i64, T, )> for StancerRouterData { @@ -20,10 +26,11 @@ impl (_currency_unit, _currency, amount, item): ( &types::api::CurrencyUnit, types::storage::enums::Currency, - i32, + 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, @@ -31,62 +38,28 @@ impl } } +//TODO: Fill the struct with respective fields #[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct StancerPaymentsRequest { - amount: i32, - currency: String, - auth: Option, - card: Option, - sepa: Option, - customer: Option, - capture: Option, - description: Option, - order_id: Option, - unique_id: Option, - return_url: Option, -} - -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct StancerAuth { - return_url: Option, - device: Option>, + amount: i64, + card: StancerCard, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct StancerCard { name: Secret, number: cards::CardNumber, - exp_month: Secret, - exp_year: Secret, + expiry_month: Secret, + expiry_year: Secret, cvc: Secret, - external_id: Option, - zip_code: Option, - customer: Option, -} - -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct StancerSepa { - name: Secret, - bic: Option, - iban: cards::CardNumber, - mandate: String, - date_mandate: String, - customer: Option, -} - -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct StancerCustomer { - email: Option, - name: Option, - mobile: Option, - date_birth: Option, - legal_id: Option, - external_id: Option, + complete: bool, } -impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for StancerPaymentsRequest { +impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for StancerPaymentsRequest { type Error = error_stack::Report; - fn try_from(item: &StancerRouterData<&types::PaymentsAuthorizeRouterData>) -> Result { + fn try_from( + item: &StancerRouterData<&types::PaymentsAuthorizeRouterData>, + ) -> Result { match item.router_data.request.payment_method_data.clone() { api::PaymentMethodData::Card(req_card) => { let card = StancerCard { @@ -107,12 +80,13 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Stance } } +//TODO: Fill the struct with respective fields // Auth Struct pub struct StancerAuthType { - pub(super) api_key: Secret + pub(super) api_key: Secret, } -impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { +impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { type Error = error_stack::Report; fn try_from(auth_type: &types::ConnectorAuthType) -> Result { match auth_type { @@ -123,63 +97,42 @@ impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { } } } - // PaymentsResponse +//TODO: Append the remaining status flags #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum StancerPaymentStatus { - Refused, - Canceled, - Authorized, - Capture_Sent, - Captured, - Disputed, + Succeeded, Failed, - Expired, #[default] - To_Capture, + Processing, } impl From for enums::AttemptStatus { fn from(item: StancerPaymentStatus) -> Self { match item { + StancerPaymentStatus::Succeeded => Self::Charged, StancerPaymentStatus::Failed => Self::Failure, - StancerPaymentStatus::Refused => Self::Failure, - StancerPaymentStatus::Expired => Self::Failure, - StancerPaymentStatus::Canceled => Self::Failure, - StancerPaymentStatus::Disputed => Self::Failure, - StancerPaymentStatus::Authorized => Self::Authorizing, - StancerPaymentStatus::To_Capture => Self::Authorizing, - StancerPaymentStatus::Capture_Sent => Self::Charged, - StancerPaymentStatus::Captured => Self::Charged, + StancerPaymentStatus::Processing => Self::Authorizing, } } } +//TODO: Fill the struct with respective fields #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct StancerPaymentsResponse { - id: String, status: StancerPaymentStatus, - response: String, - amount: i32, - currency: String, - auth: Option, - card: Option, - sepa: Option>StancerSepa>, - customer: Option, - capture: Option, - description: Option, - order_id: Option, - unique_id: Option, - date_trans: i32, - date_bank: Option, - return_url: Option, - created: i32, + id: String, } -impl TryFrom> for types::RouterData { +impl + TryFrom> + for types::RouterData +{ type Error = error_stack::Report; - fn try_from(item: types::ResponseRouterData) -> Result { + fn try_from( + item: types::ResponseRouterData, + ) -> Result { Ok(Self { status: enums::AttemptStatus::from(item.response.status), response: Ok(types::PaymentsResponseData::TransactionResponse { @@ -195,17 +148,19 @@ impl TryFromi32, - pub payment: String, + pub amount: i64, } impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRefundRequest { type Error = error_stack::Report; - fn try_from(item: &StancerRouterData<&types::RefundsRouterData>) -> Result { + fn try_from( + item: &StancerRouterData<&types::RefundsRouterData>, + ) -> Result { Ok(Self { amount: item.amount.to_owned(), }) @@ -213,39 +168,32 @@ impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRef } // Type definition for Refund Response + #[allow(dead_code)] #[derive(Debug, Serialize, Default, Deserialize, Clone)] pub enum RefundStatus { + Succeeded, Failed, - NotHonored, - RefundSent, - Refunded, #[default] - ToRefund, + Processing, } impl From for enums::RefundStatus { fn from(item: RefundStatus) -> Self { match item { - RefundStatus::Failed => Self::Failure, - RefundStatus::NotHonored => Self::Failure, - RefundStatus::ToRefund => Self::Pending, - RefundStatus::RefundSent => Self::Pending, 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 - amount: i32, - currency: String, - date_bank: i32, - date_refund: i32, - payment: String, - created: i32, + status: RefundStatus, } impl TryFrom> @@ -265,10 +213,13 @@ impl TryFrom> } } -impl TryFrom> for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { - type Error = error_stack::Report; - fn try_from(item: types::RefundsResponseRouterData) -> Result { + 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(), @@ -276,12 +227,14 @@ impl TryFrom> for t }), ..item.data }) - } - } + } +} +//TODO: Fill the struct with respective fields #[derive(Default, Debug, Serialize, Deserialize, PartialEq)] pub struct StancerErrorResponse { 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 107e8f8859d..ea5845c32c2 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1680,6 +1680,10 @@ pub(crate) fn validate_auth_and_metadata_type( square::transformers::SquareAuthType::try_from(val)?; Ok(()) } + api_enums::Connector::Stancer => { + stancer::transformers::StancerAuthType::try_from(val)?; + Ok(()) + } api_enums::Connector::Stax => { stax::transformers::StaxAuthType::try_from(val)?; Ok(()) diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index c7cca62446a..f544e6e84c9 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -142,7 +142,6 @@ impl } default_imp_for_complete_authorize!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Bankofamerica, @@ -171,6 +170,7 @@ default_imp_for_complete_authorize!( connector::Payu, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Trustpay, @@ -208,7 +208,6 @@ impl { } default_imp_for_webhook_source_verification!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -249,6 +248,7 @@ default_imp_for_webhook_source_verification!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Trustpay, @@ -288,7 +288,6 @@ impl } default_imp_for_create_customer!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -329,6 +328,7 @@ default_imp_for_create_customer!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Trustpay, connector::Tsys, connector::Volt, @@ -368,7 +368,6 @@ impl services::ConnectorRedirectResponse for connector::DummyConnec } default_imp_for_connector_redirect_response!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Bitpay, @@ -398,6 +397,7 @@ default_imp_for_connector_redirect_response!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Tsys, connector::Volt, @@ -418,7 +418,6 @@ macro_rules! default_imp_for_connector_request_id { impl api::ConnectorTransactionId for connector::DummyConnector {} default_imp_for_connector_request_id!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -458,6 +457,7 @@ default_imp_for_connector_request_id!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Trustpay, @@ -500,7 +500,6 @@ impl } default_imp_for_accept_dispute!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -541,6 +540,7 @@ default_imp_for_accept_dispute!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Trustpay, @@ -602,7 +602,6 @@ impl } default_imp_for_file_upload!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -642,6 +641,7 @@ default_imp_for_file_upload!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Trustpay, connector::Tsys, @@ -681,7 +681,6 @@ impl } default_imp_for_submit_evidence!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -721,6 +720,7 @@ default_imp_for_submit_evidence!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Trustpay, connector::Tsys, @@ -760,7 +760,6 @@ impl } default_imp_for_defend_dispute!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -800,6 +799,7 @@ default_imp_for_defend_dispute!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Trustpay, @@ -840,7 +840,6 @@ impl } default_imp_for_pre_processing_steps!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -880,6 +879,7 @@ default_imp_for_pre_processing_steps!( connector::Rapyd, connector::Shift4, connector::Square, + connector::Stancer, connector::Stax, connector::Tsys, connector::Volt, @@ -901,7 +901,6 @@ macro_rules! default_imp_for_payouts { impl api::Payouts for connector::DummyConnector {} default_imp_for_payouts!( - connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -941,6 +940,7 @@ default_imp_for_payouts!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -981,7 +981,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_create!( - connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1021,6 +1020,7 @@ default_imp_for_payouts_create!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1064,7 +1064,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_eligibility!( - connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1104,6 +1103,7 @@ default_imp_for_payouts_eligibility!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1144,7 +1144,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_fulfill!( - connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1184,6 +1183,7 @@ default_imp_for_payouts_fulfill!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1224,7 +1224,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_cancel!( - connector::Stancer, connector::Aci, connector::Airwallex, connector::Authorizedotnet, @@ -1264,6 +1263,7 @@ default_imp_for_payouts_cancel!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1304,7 +1304,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_quote!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1345,6 +1344,7 @@ default_imp_for_payouts_quote!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1385,7 +1385,6 @@ impl #[cfg(feature = "payouts")] default_imp_for_payouts_recipient!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1426,6 +1425,7 @@ default_imp_for_payouts_recipient!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1465,7 +1465,6 @@ impl } default_imp_for_approve!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1506,6 +1505,7 @@ default_imp_for_approve!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, @@ -1546,7 +1546,6 @@ impl } default_imp_for_reject!( - connector::Stancer, connector::Aci, connector::Adyen, connector::Airwallex, @@ -1587,6 +1586,7 @@ default_imp_for_reject!( connector::Prophetpay, connector::Rapyd, connector::Square, + connector::Stancer, connector::Stax, connector::Stripe, connector::Shift4, diff --git a/crates/router/src/core/payments/routing/transformers.rs b/crates/router/src/core/payments/routing/transformers.rs index 5704f82f498..329253f842b 100644 --- a/crates/router/src/core/payments/routing/transformers.rs +++ b/crates/router/src/core/payments/routing/transformers.rs @@ -109,6 +109,7 @@ impl ForeignFrom for dsl_enums::Connector { api_enums::RoutableConnectors::Rapyd => Self::Rapyd, api_enums::RoutableConnectors::Shift4 => Self::Shift4, api_enums::RoutableConnectors::Square => Self::Square, + api_enums::RoutableConnectors::Stancer => Self::Stancer, api_enums::RoutableConnectors::Stax => Self::Stax, api_enums::RoutableConnectors::Stripe => Self::Stripe, api_enums::RoutableConnectors::Trustpay => Self::Trustpay, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 19e7f34c30b..8ff1d3dc052 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -376,7 +376,7 @@ impl ConnectorData { enums::Connector::Rapyd => Ok(Box::new(&connector::Rapyd)), enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), enums::Connector::Square => Ok(Box::new(&connector::Square)), - enums::Connector::Stancer => Ok(Box::new(&connector::Stancer)), + enums::Connector::Stancer => Ok(Box::new(&connector::Stancer)), enums::Connector::Stax => Ok(Box::new(&connector::Stax)), enums::Connector::Stripe => Ok(Box::new(&connector::Stripe)), enums::Connector::Wise => Ok(Box::new(&connector::Wise)), diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 45aad93371e..c8886e613a1 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -244,6 +244,7 @@ impl ForeignTryFrom for api_enums::RoutableConnectors { .into_report()? } api_enums::Connector::Square => Self::Square, + api_enums::Connector::Stancer => Self::Stancer, api_enums::Connector::Stax => Self::Stax, api_enums::Connector::Stripe => Self::Stripe, api_enums::Connector::Trustpay => Self::Trustpay, @@ -313,6 +314,7 @@ impl ForeignFrom for api_enums::RoutableConnectors { dsl_enums::Connector::Rapyd => Self::Rapyd, dsl_enums::Connector::Shift4 => Self::Shift4, dsl_enums::Connector::Square => Self::Square, + dsl_enums::Connector::Stancer => Self::Stancer, dsl_enums::Connector::Stax => Self::Stax, dsl_enums::Connector::Stripe => Self::Stripe, dsl_enums::Connector::Trustpay => Self::Trustpay, diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs index a910a5520aa..08988766fd2 100644 --- a/crates/router/tests/connectors/main.rs +++ b/crates/router/tests/connectors/main.rs @@ -51,11 +51,11 @@ mod prophetpay; mod rapyd; mod shift4; mod square; +mod stancer; mod stax; mod stripe; mod trustpay; mod tsys; -mod stancer; mod utils; mod volt; mod wise; diff --git a/crates/router/tests/connectors/stancer.rs b/crates/router/tests/connectors/stancer.rs index 8aabaa075a7..21c50b900ce 100644 --- a/crates/router/tests/connectors/stancer.rs +++ b/crates/router/tests/connectors/stancer.rs @@ -1,11 +1,11 @@ use masking::Secret; use router::{ core::utils as core_utils, - types::{self, api, storage::enums, -}}; + types::{self, api, storage::enums}, +}; +use test_utils::connector_auth; use crate::utils::{self, ConnectorActions}; -use test_utils::connector_auth; #[derive(Clone, Copy)] struct StancerTest; @@ -17,6 +17,7 @@ impl utils::Connector for StancerTest { connector: Box::new(&Stancer), connector_name: types::Connector::Stancer, get_token: types::api::GetToken::Connector, + merchant_connector_id: None, } } @@ -24,7 +25,8 @@ impl utils::Connector for StancerTest { utils::to_connector_auth_type( connector_auth::ConnectorAuthentication::new() .stancer - .expect("Missing connector authentication configuration").into(), + .expect("Missing connector authentication configuration") + .into(), ) } @@ -127,7 +129,12 @@ async fn should_void_authorized_payment() { #[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()) + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) .await .unwrap(); assert_eq!( @@ -161,7 +168,12 @@ async fn should_partially_refund_manually_captured_payment() { #[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()) + .capture_payment_and_refund( + payment_method_details(), + None, + None, + get_default_payment_info(), + ) .await .unwrap(); let response = CONNECTOR @@ -182,14 +194,20 @@ async fn should_sync_manually_captured_refund() { // 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(); + 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(); + 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"); @@ -350,7 +368,10 @@ async fn should_fail_payment_for_incorrect_expiry_year() { // 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(); + 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"); diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index bef792d8723..0f1333bab74 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -107,7 +107,7 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" +stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" From d84f4998d1470fd8866583e20e56eaab2dc12acf Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Thu, 23 Nov 2023 22:04:12 -0500 Subject: [PATCH 13/31] add stancer models --- crates/router/src/connector/stancer.rs | 1 + crates/router/src/connector/stancer/models.rs | 1011 +++++++++++++++++ 2 files changed, 1012 insertions(+) create mode 100644 crates/router/src/connector/stancer/models.rs diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index f588d058d62..88ffe8df1c0 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -1,3 +1,4 @@ +pub mod models; pub mod transformers; use std::fmt::Debug; diff --git a/crates/router/src/connector/stancer/models.rs b/crates/router/src/connector/stancer/models.rs new file mode 100644 index 00000000000..f1eb59c8bc7 --- /dev/null +++ b/crates/router/src/connector/stancer/models.rs @@ -0,0 +1,1011 @@ +use common_utils::pii::Email; +use masking::Secret; +use serde::{Deserialize, Serialize}; + +pub mod card { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Card { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "last4")] + pub last4: String, + #[serde(rename = "brand")] + pub brand: String, + #[serde(rename = "exp_month")] + pub exp_month: i32, + #[serde(rename = "exp_year")] + pub exp_year: i32, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "funding", skip_serializing_if = "Option::is_none")] + pub funding: Option, + #[serde(rename = "nature", skip_serializing_if = "Option::is_none")] + pub nature: Option, + #[serde(rename = "network", skip_serializing_if = "Option::is_none")] + pub network: Option, + #[serde(rename = "zip_code", skip_serializing_if = "Option::is_none")] + pub zip_code: Option, + #[serde(rename = "country", skip_serializing_if = "Option::is_none")] + pub country: Option, + } + impl Card { + pub fn new( + id: String, + last4: String, + brand: String, + exp_month: i32, + exp_year: i32, + created: i32, + ) -> Card { + Card { + id, + last4, + brand, + exp_month, + exp_year, + created, + name: None, + funding: None, + nature: None, + network: None, + zip_code: None, + country: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Funding { + #[serde(rename = "credit")] + Credit, + #[serde(rename = "debit")] + Debit, + #[serde(rename = "prepaid")] + Prepaid, + #[serde(rename = "universal")] + Universal, + #[serde(rename = "charge")] + Charge, + #[serde(rename = "deferred")] + Deferred, + } + impl Default for Funding { + fn default() -> Funding { + Self::Credit + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Nature { + #[serde(rename = "personal")] + Personal, + #[serde(rename = "personnal")] + Personnal, + #[serde(rename = "corporate")] + Corporate, + } + impl Default for Nature { + fn default() -> Nature { + Self::Personal + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Network { + #[serde(rename = "national")] + National, + #[serde(rename = "mastercard")] + Mastercard, + #[serde(rename = "visa")] + Visa, + } + impl Default for Network { + fn default() -> Network { + Self::National + } + } +} +pub use self::card::Card; +pub mod create_customer_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateCustomerRequest { + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "email", skip_serializing_if = "Option::is_none")] + pub email: Option, + #[serde(rename = "mobile", skip_serializing_if = "Option::is_none")] + pub mobile: Option>, + } + impl CreateCustomerRequest { + pub fn new() -> CreateCustomerRequest { + CreateCustomerRequest { + name: None, + email: None, + mobile: None, + } + } + } +} +pub use self::create_customer_request::CreateCustomerRequest; +pub mod create_payment_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequest { + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "currency")] + pub currency: String, + #[serde(rename = "description", skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + #[serde(rename = "customer", skip_serializing_if = "Option::is_none")] + pub customer: Option, + #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] + pub sepa: Option, + #[serde(rename = "card", skip_serializing_if = "Option::is_none")] + pub card: Option>, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(rename = "methods_allowed", skip_serializing_if = "Option::is_none")] + pub methods_allowed: Option>, + #[serde(rename = "return_url", skip_serializing_if = "Option::is_none")] + pub return_url: Option, + #[serde(rename = "auth", skip_serializing_if = "Option::is_none")] + pub auth: Option>, + #[serde(rename = "device", skip_serializing_if = "Option::is_none")] + pub device: Option>, + #[serde(rename = "capture", skip_serializing_if = "Option::is_none")] + pub capture: Option, + } + impl CreatePaymentRequest { + pub fn new(amount: i32, currency: String) -> CreatePaymentRequest { + CreatePaymentRequest { + amount, + currency, + description: None, + order_id: None, + unique_id: None, + customer: None, + sepa: None, + card: None, + status: None, + methods_allowed: None, + return_url: None, + auth: None, + device: None, + capture: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "authorize")] + Authorize, + #[serde(rename = "capture")] + Capture, + } + impl Default for Status { + fn default() -> Status { + Self::Authorize + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum MethodsAllowed { + #[serde(rename = "card")] + Card, + #[serde(rename = "sepa")] + Sepa, + } + impl Default for MethodsAllowed { + fn default() -> MethodsAllowed { + Self::Card + } + } +} +pub use self::create_payment_request::CreatePaymentRequest; +pub mod create_payment_request_auth { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequestAuth { + #[serde(rename = "return_url")] + pub return_url: String, + } + impl CreatePaymentRequestAuth { + pub fn new(return_url: String) -> CreatePaymentRequestAuth { + CreatePaymentRequestAuth { return_url } + } + } +} +pub use self::create_payment_request_auth::CreatePaymentRequestAuth; +pub mod create_payment_request_card { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequestCard { + #[serde(rename = "number")] + pub number: cards::CardNumber, + #[serde(rename = "cvc")] + pub cvc: Secret, + #[serde(rename = "exp_year")] + pub exp_year: Secret, + #[serde(rename = "exp_month")] + pub exp_month: Secret, + } + impl CreatePaymentRequestCard { + pub fn new( + number: cards::CardNumber, + cvc: Secret, + exp_year: Secret, + exp_month: Secret, + ) -> CreatePaymentRequestCard { + CreatePaymentRequestCard { + number, + cvc, + exp_year, + exp_month, + } + } + } +} +pub use self::create_payment_request_card::CreatePaymentRequestCard; +pub mod create_payment_request_device { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequestDevice { + #[serde(rename = "ip")] + pub ip: String, + #[serde(rename = "port", skip_serializing_if = "Option::is_none")] + pub port: Option, + #[serde(rename = "user_agent", skip_serializing_if = "Option::is_none")] + pub user_agent: Option, + #[serde(rename = "http_accept", skip_serializing_if = "Option::is_none")] + pub http_accept: Option, + #[serde(rename = "languages", skip_serializing_if = "Option::is_none")] + pub languages: Option, + } + impl CreatePaymentRequestDevice { + pub fn new(ip: String) -> CreatePaymentRequestDevice { + CreatePaymentRequestDevice { + ip, + port: None, + user_agent: None, + http_accept: None, + languages: None, + } + } + } +} +pub use self::create_payment_request_device::CreatePaymentRequestDevice; +pub mod create_refund_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateRefundRequest { + #[serde(rename = "payment")] + pub payment: String, + #[serde(rename = "amount")] + pub amount: i32, + } + impl CreateRefundRequest { + pub fn new(payment: String, amount: i32) -> CreateRefundRequest { + CreateRefundRequest { payment, amount } + } + } +} +pub use self::create_refund_request::CreateRefundRequest; +pub mod create_sepa_409_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepa409Response { + #[serde(rename = "error")] + pub error: Box, + } + impl CreateSepa409Response { + pub fn new(error: CreateSepa409ResponseError) -> CreateSepa409Response { + CreateSepa409Response { + error: Box::new(error), + } + } + } +} +pub use self::create_sepa_409_response::CreateSepa409Response; +pub mod create_sepa_409_response_error { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepa409ResponseError { + #[serde(rename = "message")] + pub message: Box, + #[serde(rename = "type")] + pub r#type: String, + } + impl CreateSepa409ResponseError { + pub fn new( + message: CreateSepa409ResponseErrorMessage, + r#type: String, + ) -> CreateSepa409ResponseError { + CreateSepa409ResponseError { + message: Box::new(message), + r#type, + } + } + } +} +pub use self::create_sepa_409_response_error::CreateSepa409ResponseError; +pub mod create_sepa_409_response_error_message { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepa409ResponseErrorMessage { + #[serde(rename = "error")] + pub error: String, + #[serde(rename = "id")] + pub id: String, + } + impl CreateSepa409ResponseErrorMessage { + pub fn new(error: String, id: String) -> CreateSepa409ResponseErrorMessage { + CreateSepa409ResponseErrorMessage { error, id } + } + } +} +pub use self::create_sepa_409_response_error_message::CreateSepa409ResponseErrorMessage; +pub mod create_sepa_ibanonly_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepaIbanonlyRequest { + #[serde(rename = "iban")] + pub iban: String, + #[serde(rename = "name")] + pub name: String, + } + impl CreateSepaIbanonlyRequest { + pub fn new(iban: String, name: String) -> CreateSepaIbanonlyRequest { + CreateSepaIbanonlyRequest { iban, name } + } + } +} +pub use self::create_sepa_ibanonly_request::CreateSepaIbanonlyRequest; +pub mod create_sepa_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepaRequest { + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "iban")] + pub iban: String, + #[serde(rename = "bic", skip_serializing_if = "Option::is_none")] + pub bic: Option, + #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] + pub mandate: Option, + #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] + pub date_mandate: Option, + } + impl CreateSepaRequest { + pub fn new(name: String, iban: String) -> CreateSepaRequest { + CreateSepaRequest { + name, + iban, + bic: None, + mandate: None, + date_mandate: None, + } + } + } +} +pub use self::create_sepa_request::CreateSepaRequest; +pub mod customer { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Customer { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "email", skip_serializing_if = "Option::is_none")] + pub email: Option, + #[serde(rename = "mobile", skip_serializing_if = "Option::is_none")] + pub mobile: Option, + } + impl Customer { + pub fn new(id: String) -> Customer { + Customer { + id, + name: None, + email: None, + mobile: None, + } + } + } +} +pub use self::customer::Customer; +pub mod dispute { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Dispute { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "date_bank")] + pub date_bank: i32, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "payment")] + pub payment: String, + #[serde(rename = "response", skip_serializing_if = "Option::is_none")] + pub response: Option, + #[serde(rename = "type")] + pub r#type: String, + } + impl Dispute { + pub fn new( + id: String, + amount: i32, + created: i32, + date_bank: i32, + payment: String, + r#type: String, + ) -> Dispute { + Dispute { + id, + amount, + created, + date_bank, + order_id: None, + payment, + response: None, + r#type, + } + } + } +} +pub use self::dispute::Dispute; +pub mod get_disputes_200_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes200Response { + #[serde(rename = "disputes")] + pub disputes: Vec, + #[serde(rename = "range")] + pub range: Box, + } + impl GetDisputes200Response { + pub fn new( + disputes: Vec, + range: GetDisputes200ResponseRange, + ) -> GetDisputes200Response { + GetDisputes200Response { + disputes, + range: Box::new(range), + } + } + } +} +pub use self::get_disputes_200_response::GetDisputes200Response; +pub mod get_disputes_200_response_range { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes200ResponseRange { + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "start")] + pub start: i32, + #[serde(rename = "end")] + pub end: i32, + #[serde(rename = "limit")] + pub limit: i32, + #[serde(rename = "has_more")] + pub has_more: bool, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + } + impl GetDisputes200ResponseRange { + pub fn new( + created: i32, + start: i32, + end: i32, + limit: i32, + has_more: bool, + ) -> GetDisputes200ResponseRange { + GetDisputes200ResponseRange { + created, + start, + end, + limit, + has_more, + order_id: None, + unique_id: None, + } + } + } +} +pub use self::get_disputes_200_response_range::GetDisputes200ResponseRange; +pub mod get_disputes_404_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes404Response { + #[serde(rename = "error")] + pub error: Box, + } + impl GetDisputes404Response { + pub fn new(error: GetDisputes404ResponseError) -> GetDisputes404Response { + GetDisputes404Response { + error: Box::new(error), + } + } + } +} +pub use self::get_disputes_404_response::GetDisputes404Response; +pub mod get_disputes_404_response_error { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes404ResponseError { + #[serde(rename = "message")] + pub message: Box, + #[serde(rename = "type")] + pub r#type: String, + } + impl GetDisputes404ResponseError { + pub fn new( + message: GetDisputes404ResponseErrorMessage, + r#type: String, + ) -> GetDisputes404ResponseError { + GetDisputes404ResponseError { + message: Box::new(message), + r#type, + } + } + } +} +pub use self::get_disputes_404_response_error::GetDisputes404ResponseError; +pub mod get_disputes_404_response_error_message { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes404ResponseErrorMessage { + #[serde(rename = "id")] + pub id: String, + } + impl GetDisputes404ResponseErrorMessage { + pub fn new(id: String) -> GetDisputes404ResponseErrorMessage { + GetDisputes404ResponseErrorMessage { id } + } + } +} +pub use self::get_disputes_404_response_error_message::GetDisputes404ResponseErrorMessage; +pub mod list_payments_200_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct ListPayments200Response { + #[serde(rename = "live_mode")] + pub live_mode: bool, + #[serde(rename = "payments")] + pub payments: Vec, + #[serde(rename = "range")] + pub range: Box, + } + impl ListPayments200Response { + pub fn new( + live_mode: bool, + payments: Vec, + range: ListPayments200ResponseRange, + ) -> ListPayments200Response { + ListPayments200Response { + live_mode, + payments, + range: Box::new(range), + } + } + } +} +pub use self::list_payments_200_response::ListPayments200Response; +pub mod list_payments_200_response_range { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct ListPayments200ResponseRange { + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "start")] + pub start: i32, + #[serde(rename = "end")] + pub end: i32, + #[serde(rename = "has_more")] + pub has_more: bool, + #[serde(rename = "limit")] + pub limit: i32, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + } + impl ListPayments200ResponseRange { + pub fn new( + created: i32, + start: i32, + end: i32, + has_more: bool, + limit: i32, + ) -> ListPayments200ResponseRange { + ListPayments200ResponseRange { + created, + start, + end, + has_more, + limit, + order_id: None, + unique_id: None, + } + } + } +} +pub use self::list_payments_200_response_range::ListPayments200ResponseRange; +pub mod payment { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Payment { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "currency")] + pub currency: String, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "fee", skip_serializing_if = "Option::is_none")] + pub fee: Option, + #[serde(rename = "description", skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + #[serde(rename = "method", skip_serializing_if = "Option::is_none")] + pub method: Option, + #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] + pub sepa: Option>, + #[serde(rename = "card", skip_serializing_if = "Option::is_none")] + pub card: Option>, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(rename = "response", skip_serializing_if = "Option::is_none")] + pub response: Option, + #[serde(rename = "methods_allowed", skip_serializing_if = "Option::is_none")] + pub methods_allowed: Option>, + #[serde(rename = "return_url", skip_serializing_if = "Option::is_none")] + pub return_url: Option, + #[serde(rename = "auth", skip_serializing_if = "Option::is_none")] + pub auth: Option>, + #[serde(rename = "device", skip_serializing_if = "Option::is_none")] + pub device: Option>, + #[serde(rename = "customer", skip_serializing_if = "Option::is_none")] + pub customer: Option>, + } + impl Payment { + pub fn new(id: String, amount: i32, currency: String, created: i32) -> Payment { + Payment { + id, + amount, + currency, + created, + fee: None, + description: None, + order_id: None, + unique_id: None, + method: None, + sepa: None, + card: None, + status: None, + response: None, + methods_allowed: None, + return_url: None, + auth: None, + device: None, + customer: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Method { + #[serde(rename = "sepa")] + Sepa, + #[serde(rename = "card")] + Card, + } + impl Default for Method { + fn default() -> Method { + Self::Sepa + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "authorized")] + Authorized, + #[serde(rename = "canceled")] + Canceled, + #[serde(rename = "captured")] + Captured, + #[serde(rename = "capture_sent")] + CaptureSent, + #[serde(rename = "disputed")] + Disputed, + #[serde(rename = "expired")] + Expired, + #[serde(rename = "failed")] + Failed, + #[serde(rename = "refused")] + Refused, + #[serde(rename = "to_capture")] + ToCapture, + } + impl Default for Status { + fn default() -> Status { + Self::Authorized + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum MethodsAllowed { + #[serde(rename = "card")] + Card, + #[serde(rename = "sepa")] + Sepa, + } + impl Default for MethodsAllowed { + fn default() -> MethodsAllowed { + Self::Card + } + } +} +pub use self::payment::Payment; +pub mod payment_auth { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct PaymentAuth { + #[serde(rename = "redirect_url")] + pub redirect_url: String, + #[serde(rename = "return_url")] + pub return_url: String, + #[serde(rename = "status")] + pub status: Status, + } + impl PaymentAuth { + pub fn new(redirect_url: String, return_url: String, status: Status) -> PaymentAuth { + PaymentAuth { + redirect_url, + return_url, + status, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "attempted")] + Attempted, + #[serde(rename = "available")] + Available, + #[serde(rename = "declined")] + Declined, + #[serde(rename = "expired")] + Expired, + #[serde(rename = "failed")] + Failed, + #[serde(rename = "requested")] + Requested, + #[serde(rename = "success")] + Success, + #[serde(rename = "unavailable")] + Unavailable, + } + impl Default for Status { + fn default() -> Status { + Self::Attempted + } + } +} +pub use self::payment_auth::PaymentAuth; +pub mod payment_device { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct PaymentDevice { + #[serde(rename = "ip")] + pub ip: String, + #[serde(rename = "port", skip_serializing_if = "Option::is_none")] + pub port: Option, + #[serde(rename = "user_agent", skip_serializing_if = "Option::is_none")] + pub user_agent: Option, + #[serde(rename = "http_accept", skip_serializing_if = "Option::is_none")] + pub http_accept: Option, + #[serde(rename = "languages", skip_serializing_if = "Option::is_none")] + pub languages: Option, + #[serde(rename = "city", skip_serializing_if = "Option::is_none")] + pub city: Option, + #[serde(rename = "country", skip_serializing_if = "Option::is_none")] + pub country: Option, + } + impl PaymentDevice { + pub fn new(ip: String) -> PaymentDevice { + PaymentDevice { + ip, + port: None, + user_agent: None, + http_accept: None, + languages: None, + city: None, + country: None, + } + } + } +} +pub use self::payment_device::PaymentDevice; +pub mod refund { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Refund { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "payment")] + pub payment: String, + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "currency")] + pub currency: String, + #[serde(rename = "status")] + pub status: Status, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "date_refund", skip_serializing_if = "Option::is_none")] + pub date_refund: Option, + #[serde(rename = "date_bank", skip_serializing_if = "Option::is_none")] + pub date_bank: Option, + #[serde(rename = "live_mode", skip_serializing_if = "Option::is_none")] + pub live_mode: Option, + } + impl Refund { + pub fn new( + id: String, + payment: String, + amount: i32, + currency: String, + status: Status, + created: i32, + ) -> Refund { + Refund { + id, + payment, + amount, + currency, + status, + created, + date_refund: None, + date_bank: None, + live_mode: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "failed")] + Failed, + #[serde(rename = "not_honored")] + NotHonored, + #[serde(rename = "refund_sent")] + RefundSent, + #[serde(rename = "refunded")] + Refunded, + #[serde(rename = "to_refund")] + ToRefund, + } + impl Default for Status { + fn default() -> Status { + Self::Failed + } + } +} +pub use self::refund::Refund; +pub mod sepa { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Sepa { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "last4")] + pub last4: String, + #[serde(rename = "bic", skip_serializing_if = "Option::is_none")] + pub bic: Option, + #[serde(rename = "live_mode", skip_serializing_if = "Option::is_none")] + pub live_mode: Option, + #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] + pub mandate: Option, + #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] + pub date_mandate: Option, + } + impl Sepa { + pub fn new(id: String, name: String, created: i32, last4: String) -> Sepa { + Sepa { + id, + name, + created, + last4, + bic: None, + live_mode: None, + mandate: None, + date_mandate: None, + } + } + } +} +pub use self::sepa::Sepa; +pub mod update_payment_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct UpdatePaymentRequest { + #[serde(rename = "amount", skip_serializing_if = "Option::is_none")] + pub amount: Option, + #[serde(rename = "currency", skip_serializing_if = "Option::is_none")] + pub currency: Option, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "description", skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] + pub sepa: Option, + #[serde(rename = "card", skip_serializing_if = "Option::is_none")] + pub card: Option, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + } + impl UpdatePaymentRequest { + pub fn new() -> UpdatePaymentRequest { + UpdatePaymentRequest { + amount: None, + currency: None, + order_id: None, + description: None, + sepa: None, + card: None, + status: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "authorize")] + Authorize, + #[serde(rename = "capture")] + Capture, + } + impl Default for Status { + fn default() -> Status { + Self::Authorize + } + } +} +pub use self::update_payment_request::UpdatePaymentRequest; +pub mod update_sepa_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct UpdateSepaRequest { + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] + pub mandate: Option, + #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] + pub date_mandate: Option, + } + impl UpdateSepaRequest { + pub fn new() -> UpdateSepaRequest { + UpdateSepaRequest { + name: None, + mandate: None, + date_mandate: None, + } + } + } +} +pub use self::update_sepa_request::UpdateSepaRequest; From 56ad3200a95f991e7018f9df2e0cf0aa250919ca Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Tue, 21 Nov 2023 22:07:51 -0500 Subject: [PATCH 14/31] set currency unit + format auth headers (cherry picked from commit 31c08e0406c0f6d410833ec5c0d4bc2fb2dbaceb) --- crates/router/src/connector/stancer.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 88ffe8df1c0..b9e4919fc65 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -3,12 +3,14 @@ pub mod transformers; use std::fmt::Debug; +use base64::Engine; use error_stack::{IntoReport, ResultExt}; -use masking::ExposeInterface; +use masking::PeekInterface; use transformers as stancer; use crate::{ configs::settings, + consts, core::errors::{self, CustomResult}, headers, services::{ @@ -75,10 +77,7 @@ impl ConnectorCommon for Stancer { } 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 + api::CurrencyUnit::Minor } fn common_get_content_type(&self) -> &'static str { @@ -95,9 +94,14 @@ impl ConnectorCommon for Stancer { ) -> CustomResult)>, errors::ConnectorError> { let auth = stancer::StancerAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + Ok(vec![( headers::AUTHORIZATION.to_string(), - auth.api_key.expose().into_masked(), + format!( + "Basic {}", + consts::BASE64_ENGINE.encode(format!("{}:", auth.api_key.peek())) + ) + .into_masked(), )]) } From 6dc83d6a8289f22be24592a35f8be5e37f09e933 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 23:01:53 -0500 Subject: [PATCH 15/31] implement `ConnectorValidation` (cherry picked from commit e5245ec46461582117923822afa0a52ccdde7951) --- crates/router/src/connector/stancer.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index b9e4919fc65..7694f004d28 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -21,6 +21,7 @@ use crate::{ types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, + storage::enums, ErrorResponse, Response, }, utils::{self, BytesExt}, @@ -125,7 +126,22 @@ impl ConnectorCommon for Stancer { } impl ConnectorValidation for Stancer { - //TODO: implement functions when support enabled + fn validate_capture_method( + &self, + capture_method: 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(errors::ConnectorError::NotSupported { + message: capture_method.to_string(), + connector: self.id(), + } + .into()) + } + } + } } impl ConnectorIntegration From 28a4370aaa9bcc1a303a09a26e7fb41bada5a5fc Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Thu, 23 Nov 2023 18:14:21 -0500 Subject: [PATCH 16/31] add generic error response (cherry picked from commit 2282207dd9a93169cfe9da1daed72d9178f4d05a) --- crates/router/src/connector/stancer.rs | 10 +++++++--- .../router/src/connector/stancer/transformers.rs | 15 ++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 7694f004d28..03bd8fcddbe 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -114,12 +114,16 @@ impl ConnectorCommon for Stancer { .response .parse_struct("StancerErrorResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let stancer::StancerErrorResponse::Error { + message, + error_type, + } = response; Ok(ErrorResponse { status_code: res.status_code, - code: response.code, - message: response.message, - reason: response.reason, + code: error_type, + message: message.to_string(), + reason: None, attempt_status: None, }) } diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index e0c4f58c890..f75f19370ce 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -230,11 +230,12 @@ impl TryFrom> } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct StancerErrorResponse { - pub status_code: u16, - pub code: String, - pub message: String, - pub reason: Option, +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum StancerErrorResponse { + Error { + message: serde_json::Value, + #[serde(rename = "type")] + error_type: String, + }, } From 513fa44ccee98da7d61d5ce51e529521e033a7d8 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 14:37:02 -0500 Subject: [PATCH 17/31] change amount type in router data + transform `CreatePaymentRequest` (cherry picked from commit 35fcb6c7ee4af951e8e89415ce061a30e375ce3e) --- crates/router/src/connector/stancer.rs | 6 +- .../src/connector/stancer/transformers.rs | 121 ++++++++++++------ 2 files changed, 86 insertions(+), 41 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 03bd8fcddbe..8c5b2b68912 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -27,6 +27,8 @@ use crate::{ utils::{self, BytesExt}, }; +use self::models::CreatePaymentRequest; + #[derive(Debug, Clone)] pub struct Stancer; @@ -202,10 +204,10 @@ impl ConnectorIntegration::encode_to_string_of_json, + utils::Encode::::encode_to_string_of_json, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(stancer_req)) diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index f75f19370ce..8f7bd512835 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -1,15 +1,17 @@ use masking::Secret; use serde::{Deserialize, Serialize}; +use super::models::{ + CreatePaymentRequest, CreatePaymentRequestAuth, CreatePaymentRequestCard, + CreatePaymentRequestDevice, +}; use crate::{ - connector::utils::PaymentsAuthorizeRequestData, core::errors, types::{self, api, storage::enums}, }; -//TODO: Fill the struct with respective fields pub struct StancerRouterData { - pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub amount: i32, pub router_data: T, } @@ -30,51 +32,89 @@ impl T, ), ) -> Result { - //Todo : use utils to convert the amount to the type of amount that a connector accepts Ok(Self { - amount, + amount: amount + .try_into() + .map_err(|_| errors::ConnectorError::ParsingFailed)?, router_data: item, }) } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct StancerPaymentsRequest { - amount: i64, - card: StancerCard, -} - -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct StancerCard { - name: Secret, - number: cards::CardNumber, - expiry_month: Secret, - expiry_year: Secret, - cvc: Secret, - complete: bool, -} - -impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for StancerPaymentsRequest { +// CreatePaymentRequest +impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for CreatePaymentRequest { type Error = error_stack::Report; fn try_from( item: &StancerRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { - match item.router_data.request.payment_method_data.clone() { - api::PaymentMethodData::Card(req_card) => { - let card = StancerCard { - name: req_card.card_holder_name, - 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, - }) - } + let StancerRouterData { + amount, + router_data, + } = item; + let request = CreatePaymentRequest { + description: router_data.description.to_owned(), + order_id: Some(router_data.connector_request_reference_id.to_owned()), + unique_id: Some(router_data.payment_id.to_owned()), + capture: router_data.request.capture_method.map( + |capture_method| match capture_method { + common_enums::CaptureMethod::Automatic => true, + common_enums::CaptureMethod::Manual + | common_enums::CaptureMethod::ManualMultiple + | common_enums::CaptureMethod::Scheduled => false, + }, + ), + customer: router_data.connector_customer.to_owned(), + ..CreatePaymentRequest::new( + *amount, + router_data.request.currency.to_string().to_lowercase(), + ) + }; + let use_3ds = matches!( + router_data.auth_type, + common_enums::AuthenticationType::ThreeDs + ); + + match &router_data.request.payment_method_data { + api::PaymentMethodData::Card(card) => Ok(CreatePaymentRequest { + card: Some( + CreatePaymentRequestCard { + number: card.card_number.to_owned(), + cvc: card.card_cvc.to_owned(), + exp_year: card.card_exp_year.to_owned(), + exp_month: card.card_exp_month.to_owned(), + } + .into(), + ), + auth: use_3ds + .then(|| { + router_data + .return_url + .to_owned() + .map(|return_url| CreatePaymentRequestAuth { return_url }.into()) + }) + .flatten(), + device: use_3ds + .then(|| { + router_data + .request + .browser_info + .as_ref() + .and_then(|browser_info| { + Some( + CreatePaymentRequestDevice { + ip: browser_info.ip_address.as_ref()?.to_string(), + port: None, + user_agent: browser_info.user_agent.to_owned(), + http_accept: browser_info.accept_header.to_owned(), + languages: browser_info.language.to_owned(), + } + .into(), + ) + }) + }) + .flatten(), + ..request + }), _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), } } @@ -162,7 +202,10 @@ impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRef item: &StancerRouterData<&types::RefundsRouterData>, ) -> Result { Ok(Self { - amount: item.amount.to_owned(), + amount: item + .amount + .try_into() + .map_err(|_| errors::ConnectorError::ParsingFailed)?, }) } } From e810e2551fbd4a954c7a59935470d9b7c2cb2408 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 16:44:46 -0500 Subject: [PATCH 18/31] tranform `Payment` (cherry picked from commit 1a5e442b45bf28107eec773614f6817c376b8e1c) --- crates/router/src/connector/stancer.rs | 14 ++-- .../src/connector/stancer/transformers.rs | 82 +++++++++++-------- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 8c5b2b68912..93f46c6a94e 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -27,7 +27,7 @@ use crate::{ utils::{self, BytesExt}, }; -use self::models::CreatePaymentRequest; +use self::models::{CreatePaymentRequest, Payment}; #[derive(Debug, Clone)] pub struct Stancer; @@ -240,9 +240,9 @@ impl ConnectorIntegration CustomResult { - let response: stancer::StancerPaymentsResponse = res + let response: Payment = res .response - .parse_struct("Stancer PaymentsAuthorizeResponse") + .parse_struct("stancer Payment") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, @@ -302,9 +302,9 @@ impl ConnectorIntegration CustomResult { - let response: stancer::StancerPaymentsResponse = res + let response: Payment = res .response - .parse_struct("stancer PaymentsSyncResponse") + .parse_struct("stancer Payment") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, @@ -377,9 +377,9 @@ impl ConnectorIntegration CustomResult { - let response: stancer::StancerPaymentsResponse = res + let response: Payment = res .response - .parse_struct("Stancer PaymentsCaptureResponse") + .parse_struct("Stancer Payment") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 8f7bd512835..554e6197f42 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -2,11 +2,12 @@ use masking::Secret; use serde::{Deserialize, Serialize}; use super::models::{ - CreatePaymentRequest, CreatePaymentRequestAuth, CreatePaymentRequestCard, - CreatePaymentRequestDevice, + payment, payment_auth, CreatePaymentRequest, CreatePaymentRequestAuth, + CreatePaymentRequestCard, CreatePaymentRequestDevice, Payment, }; use crate::{ core::errors, + services, types::{self, api, storage::enums}, }; @@ -120,7 +121,6 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Create } } -//TODO: Fill the struct with respective fields // Auth Struct pub struct StancerAuthType { pub(super) api_key: Secret, @@ -137,51 +137,69 @@ impl TryFrom<&types::ConnectorAuthType> for StancerAuthType { } } } -// PaymentsResponse -//TODO: Append the remaining status flags -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum StancerPaymentStatus { - Succeeded, - Failed, - #[default] - Processing, -} - -impl From for enums::AttemptStatus { - fn from(item: StancerPaymentStatus) -> Self { - match item { - StancerPaymentStatus::Succeeded => Self::Charged, - StancerPaymentStatus::Failed => Self::Failure, - StancerPaymentStatus::Processing => Self::Authorizing, +// Payment +impl From for enums::AttemptStatus { + fn from(value: payment::Status) -> Self { + match value { + payment::Status::Authorized => Self::Authorized, + payment::Status::Canceled | payment::Status::Expired => Self::Voided, + payment::Status::Captured => Self::Charged, + payment::Status::ToCapture | payment::Status::CaptureSent => Self::CaptureInitiated, + payment::Status::Refused | payment::Status::Failed => Self::Failure, + payment::Status::Disputed => Self::AutoRefunded, } } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct StancerPaymentsResponse { - status: StancerPaymentStatus, - id: String, +impl From for enums::AttemptStatus { + fn from(value: payment_auth::Status) -> Self { + match value { + payment_auth::Status::Attempted + | payment_auth::Status::Available + | payment_auth::Status::Requested => Self::AuthenticationPending, + payment_auth::Status::Declined + | payment_auth::Status::Failed + | payment_auth::Status::Unavailable => Self::AuthenticationFailed, + payment_auth::Status::Expired => Self::Voided, + payment_auth::Status::Success => Self::AuthenticationSuccessful, + } + } } -impl - TryFrom> +impl TryFrom> for types::RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: types::ResponseRouterData, ) -> Result { + let types::ResponseRouterData::<_, _, _, _> { response, .. } = item; + let Payment { + status, auth, id, .. + } = response; + Ok(Self { - status: enums::AttemptStatus::from(item.response.status), + status: status + .map(Into::into) + .or(auth.as_ref().map(|auth| auth.status).map(Into::into)) + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "status", + })?, response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data: None, + resource_id: types::ResponseId::ConnectorTransactionId(id.to_owned()), + redirection_data: auth + .map(|auth| { + url::Url::parse(&auth.redirect_url) + .map_err(|_| errors::ConnectorError::ParsingFailed) + }) + .transpose()? + .map(|redirect_url| { + services::RedirectForm::from((redirect_url, services::Method::Get)) + }), mandate_reference: None, connector_metadata: None, network_txn_id: None, - connector_response_reference_id: None, + connector_response_reference_id: Some(id), }), ..item.data }) From 2a55bba963f3ae380651bc7fe5d4efdbdde84ba4 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 19:44:46 -0500 Subject: [PATCH 19/31] tranform `Refund` (cherry picked from commit 6eda4ca28d00d0325438c6b92bef72451cc66864) --- crates/router/src/connector/stancer.rs | 14 ++-- .../src/connector/stancer/transformers.rs | 68 +++++++------------ 2 files changed, 30 insertions(+), 52 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 93f46c6a94e..1b0f3dcc28f 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -27,7 +27,7 @@ use crate::{ utils::{self, BytesExt}, }; -use self::models::{CreatePaymentRequest, Payment}; +use self::models::{CreatePaymentRequest, CreateRefundRequest, Payment, Refund}; #[derive(Debug, Clone)] pub struct Stancer; @@ -435,10 +435,10 @@ impl ConnectorIntegration::encode_to_string_of_json, + utils::Encode::::encode_to_string_of_json, ) .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(stancer_req)) @@ -468,9 +468,9 @@ impl ConnectorIntegration, res: Response, ) -> CustomResult, errors::ConnectorError> { - let response: stancer::RefundResponse = res + let response: Refund = res .response - .parse_struct("stancer RefundResponse") + .parse_struct("stancer Refund") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, @@ -531,9 +531,9 @@ impl ConnectorIntegration CustomResult { - let response: stancer::RefundResponse = res + let response: Refund = res .response - .parse_struct("stancer RefundSyncResponse") + .parse_struct("stancer Refund") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 554e6197f42..454c94c7caf 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -2,8 +2,8 @@ use masking::Secret; use serde::{Deserialize, Serialize}; use super::models::{ - payment, payment_auth, CreatePaymentRequest, CreatePaymentRequestAuth, - CreatePaymentRequestCard, CreatePaymentRequestDevice, Payment, + payment, payment_auth, refund, CreatePaymentRequest, CreatePaymentRequestAuth, + CreatePaymentRequestCard, CreatePaymentRequestDevice, CreateRefundRequest, Payment, Refund, }; use crate::{ core::errors, @@ -206,67 +206,45 @@ impl TryFrom TryFrom<&StancerRouterData<&types::RefundsRouterData>> for StancerRefundRequest { +// CreateRefundRequest +impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for CreateRefundRequest { type Error = error_stack::Report; fn try_from( item: &StancerRouterData<&types::RefundsRouterData>, ) -> Result { + let StancerRouterData { + amount, + router_data, + } = item; + Ok(Self { - amount: item - .amount - .try_into() - .map_err(|_| errors::ConnectorError::ParsingFailed)?, + amount: *amount, + payment: router_data.request.connector_transaction_id.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 { +// Refund +impl From for enums::RefundStatus { + fn from(item: refund::Status) -> Self { match item { - RefundStatus::Succeeded => Self::Success, - RefundStatus::Failed => Self::Failure, - RefundStatus::Processing => Self::Pending, - //TODO: Review mapping + refund::Status::Failed | refund::Status::NotHonored => Self::Failure, + refund::Status::RefundSent | refund::Status::ToRefund => Self::Pending, + refund::Status::Refunded => Self::Success, } } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct RefundResponse { - id: String, - status: RefundStatus, -} - -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.id, refund_status: enums::RefundStatus::from(item.response.status), }), ..item.data @@ -274,16 +252,16 @@ impl TryFrom> } } -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.id, refund_status: enums::RefundStatus::from(item.response.status), }), ..item.data From bb921d9d5f8271acf758be8743bcbd92bbb4a7b4 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 20:08:19 -0500 Subject: [PATCH 20/31] update `get_url` for authorize flow (cherry picked from commit 477a2c5148603421039be81db666be9323d842b1) --- crates/router/src/connector/stancer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 1b0f3dcc28f..c904150adda 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -188,9 +188,9 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!("{}{}", self.base_url(connectors), "v1/checkout")) } fn get_request_body( From 8628f977499c573f7271ad328885c42036fabba9 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 20:15:11 -0500 Subject: [PATCH 21/31] update url for payment sync flow (cherry picked from commit 2347c7588d56d8910e03d6b6339ede2c3225b83f) --- crates/router/src/connector/stancer.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index c904150adda..d2973861cdf 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -29,6 +29,8 @@ use crate::{ use self::models::{CreatePaymentRequest, CreateRefundRequest, Payment, Refund}; +use super::utils::PaymentsSyncRequestData; + #[derive(Debug, Clone)] pub struct Stancer; @@ -276,10 +278,15 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!( + "{}{}/{}", + self.base_url(_connectors), + "v1/checkout", + req.request.get_connector_transaction_id()? + )) } fn build_request( From 611865e0ba674886ce6d0d04d8a22d576ec6699b Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 21:19:44 -0500 Subject: [PATCH 22/31] transform `UpdatePaymentRequest` + update impl of capture flow (cherry picked from commit fa17be77d46f3bfa7caeb8981093284f0efd8576) --- crates/router/src/connector/stancer.rs | 31 +++++++++++++++---- .../src/connector/stancer/transformers.rs | 22 +++++++++++-- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index d2973861cdf..9dee35bc97c 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -27,7 +27,9 @@ use crate::{ utils::{self, BytesExt}, }; -use self::models::{CreatePaymentRequest, CreateRefundRequest, Payment, Refund}; +use self::models::{ + CreatePaymentRequest, CreateRefundRequest, Payment, Refund, UpdatePaymentRequest, +}; use super::utils::PaymentsSyncRequestData; @@ -345,18 +347,35 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!( + "{}{}/{}", + self.base_url(connectors), + "v1/checkout", + req.request.connector_transaction_id + )) } fn get_request_body( &self, - _req: &types::PaymentsCaptureRouterData, + req: &types::PaymentsCaptureRouterData, _connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + let connector_router_data = stancer::StancerRouterData::try_from(( + &self.get_currency_unit(), + req.request.currency, + req.request.amount_to_capture, + req, + ))?; + let req_obj = UpdatePaymentRequest::try_from(&connector_router_data)?; + let stancer_req = types::RequestBody::log_and_get_request_body( + &req_obj, + utils::Encode::::encode_to_string_of_json, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(stancer_req)) } fn build_request( diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 454c94c7caf..fcc225418aa 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -2,8 +2,9 @@ use masking::Secret; use serde::{Deserialize, Serialize}; use super::models::{ - payment, payment_auth, refund, CreatePaymentRequest, CreatePaymentRequestAuth, - CreatePaymentRequestCard, CreatePaymentRequestDevice, CreateRefundRequest, Payment, Refund, + payment, payment_auth, refund, update_payment_request, CreatePaymentRequest, + CreatePaymentRequestAuth, CreatePaymentRequestCard, CreatePaymentRequestDevice, + CreateRefundRequest, Payment, Refund, UpdatePaymentRequest, }; use crate::{ core::errors, @@ -121,6 +122,23 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Create } } +// UpdatePaymentRequest +impl TryFrom<&StancerRouterData<&types::PaymentsCaptureRouterData>> for UpdatePaymentRequest { + type Error = error_stack::Report; + + fn try_from( + item: &StancerRouterData<&types::PaymentsCaptureRouterData>, + ) -> Result { + let StancerRouterData { amount, .. } = item; + + Ok(Self { + amount: Some(*amount), + status: Some(update_payment_request::Status::Capture), + ..UpdatePaymentRequest::new() + }) + } +} + // Auth Struct pub struct StancerAuthType { pub(super) api_key: Secret, From 691123a2ba28f24ed6c0bdf2dc046f4871aa4d80 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Wed, 22 Nov 2023 22:37:34 -0500 Subject: [PATCH 23/31] update url for refund & refund sync flows (cherry picked from commit 17bb0bec52c4b2e17ad8e411552555f5ce0e0525) --- crates/router/src/connector/stancer.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 9dee35bc97c..e4ae4557a8f 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -31,7 +31,7 @@ use self::models::{ CreatePaymentRequest, CreateRefundRequest, Payment, Refund, UpdatePaymentRequest, }; -use super::utils::PaymentsSyncRequestData; +use super::utils::{PaymentsSyncRequestData, RefundsRequestData}; #[derive(Debug, Clone)] pub struct Stancer; @@ -447,7 +447,7 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!("{}{}", self.base_url(_connectors), "v1/refunds")) } fn get_request_body( @@ -528,10 +528,15 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!( + "{}{}/{}", + self.base_url(connectors), + "v1/refunds", + req.request.get_connector_refund_id()? + )) } fn build_request( From 4c9d4333985eeb67e942db70c18721f91f506b8f Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Thu, 23 Nov 2023 00:25:30 -0500 Subject: [PATCH 24/31] add `ConnectorCustomer` flow (cherry picked from commit 96ba6ce1cf0618f112ff5b139788b4e6bedafc07) --- crates/router/src/connector/stancer.rs | 93 ++++++++++++++++++- .../src/connector/stancer/transformers.rs | 36 ++++++- crates/router/src/core/payments/flows.rs | 1 - 3 files changed, 125 insertions(+), 5 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index e4ae4557a8f..b69200e65bc 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -28,7 +28,8 @@ use crate::{ }; use self::models::{ - CreatePaymentRequest, CreateRefundRequest, Payment, Refund, UpdatePaymentRequest, + CreateCustomerRequest, CreatePaymentRequest, CreateRefundRequest, Customer, Payment, Refund, + UpdatePaymentRequest, }; use super::utils::{PaymentsSyncRequestData, RefundsRequestData}; @@ -48,6 +49,7 @@ impl api::Refund for Stancer {} impl api::RefundExecute for Stancer {} impl api::RefundSync for Stancer {} impl api::PaymentToken for Stancer {} +impl api::ConnectorCustomer for Stancer {} impl ConnectorIntegration< @@ -581,6 +583,95 @@ impl ConnectorIntegration for Stancer +{ + fn get_headers( + &self, + req: &types::ConnectorCustomerRouterData, + 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::ConnectorCustomerRouterData, + connectors: &settings::Connectors, + ) -> CustomResult { + Ok(format!("{}{}", self.base_url(connectors), "v1/customers",)) + } + + fn get_request_body( + &self, + req: &types::ConnectorCustomerRouterData, + _connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + let connector_request = CreateCustomerRequest::try_from(req)?; + let stancer_req = types::RequestBody::log_and_get_request_body( + &connector_request, + utils::Encode::::url_encode, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(stancer_req)) + } + + fn build_request( + &self, + req: &types::ConnectorCustomerRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = services::RequestBuilder::new() + .method(services::Method::Post) + .url(&types::ConnectorCustomerType::get_url( + self, req, connectors, + )?) + .attach_default_headers() + .headers(types::ConnectorCustomerType::get_headers( + self, req, connectors, + )?) + .body(types::ConnectorCustomerType::get_request_body( + self, req, connectors, + )?) + .build(); + Ok(Some(request)) + } + + fn handle_response( + &self, + data: &types::ConnectorCustomerRouterData, + res: Response, + ) -> CustomResult + where + types::PaymentsResponseData: Clone, + { + let response: Customer = res + .response + .parse_struct("stancer Customer") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }) + } + + fn get_error_response( + &self, + res: Response, + ) -> CustomResult { + self.build_error_response(res) + } +} + #[async_trait::async_trait] impl api::IncomingWebhook for Stancer { fn get_webhook_object_reference_id( diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index fcc225418aa..70f0ea6f2e2 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -2,9 +2,10 @@ use masking::Secret; use serde::{Deserialize, Serialize}; use super::models::{ - payment, payment_auth, refund, update_payment_request, CreatePaymentRequest, - CreatePaymentRequestAuth, CreatePaymentRequestCard, CreatePaymentRequestDevice, - CreateRefundRequest, Payment, Refund, UpdatePaymentRequest, + payment, payment_auth, refund, update_payment_request, CreateCustomerRequest, + CreatePaymentRequest, CreatePaymentRequestAuth, CreatePaymentRequestCard, + CreatePaymentRequestDevice, CreateRefundRequest, Customer, Payment, Refund, + UpdatePaymentRequest, }; use crate::{ core::errors, @@ -287,6 +288,35 @@ impl TryFrom> } } +// CreateCustomerRequest +impl TryFrom<&types::ConnectorCustomerRouterData> for CreateCustomerRequest { + type Error = error_stack::Report; + fn try_from(item: &types::ConnectorCustomerRouterData) -> Result { + Ok(Self { + name: item.request.name.to_owned(), + email: item.request.email.to_owned(), + mobile: item.request.phone.to_owned(), + }) + } +} + +// Customer +impl TryFrom> + for types::RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::ResponseRouterData, + ) -> Result { + Ok(Self { + response: Ok(types::PaymentsResponseData::ConnectorCustomerResponse { + connector_customer_id: item.response.id, + }), + ..item.data + }) + } +} + #[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum StancerErrorResponse { diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index f544e6e84c9..b3d5b57e0e3 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -328,7 +328,6 @@ default_imp_for_create_customer!( connector::Rapyd, connector::Shift4, connector::Square, - connector::Stancer, connector::Trustpay, connector::Tsys, connector::Volt, From c388b2789874db84ddd409e86739ac49a8f74b21 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Fri, 24 Nov 2023 01:04:57 -0500 Subject: [PATCH 25/31] remove duplicated urls --- config/config.example.toml | 3 +-- config/development.toml | 3 +-- config/docker_compose.toml | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 9dbe3d9053c..81d9cf3a914 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -206,9 +206,8 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" +stancer.base_url = "https://api.stancer.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" stripe.base_url_file_upload = "https://files.stripe.com/" diff --git a/config/development.toml b/config/development.toml index 6342d162fca..231d4f22ab8 100644 --- a/config/development.toml +++ b/config/development.toml @@ -181,9 +181,8 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" +stancer.base_url = "https://api.stancer.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" stripe.base_url_file_upload = "https://files.stripe.com/" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index eaf797e8b63..f6e04c3d855 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -121,9 +121,8 @@ prophetpay.base_url = "https://ccm-thirdparty.cps.golf/" rapyd.base_url = "https://sandboxapi.rapyd.net" shift4.base_url = "https://api.shift4.com/" square.base_url = "https://connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com/" square.secondary_base_url = "https://pci-connect.squareupsandbox.com/" -stancer.base_url = "https://api.stancer.com" +stancer.base_url = "https://api.stancer.com/" stax.base_url = "https://apiprod.fattlabs.com/" stripe.base_url = "https://api.stripe.com/" stripe.base_url_file_upload = "https://files.stripe.com/" From 1eea0052783a1d99f0a9293a6659170e6b6efe7b Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Fri, 24 Nov 2023 01:06:12 -0500 Subject: [PATCH 26/31] downgrade 3ds request if not enrolled --- crates/router/src/connector/stancer.rs | 45 ++++++++++++++++- .../src/connector/stancer/transformers.rs | 48 ++++++++++++------- 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index b69200e65bc..70ba543249d 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -11,8 +11,11 @@ use transformers as stancer; use crate::{ configs::settings, consts, - core::errors::{self, CustomResult}, - headers, + core::{ + errors::{self, CustomResult}, + payments, + }, + headers, routes, services::{ self, request::{self, Mask}, @@ -176,6 +179,7 @@ impl { } +#[async_trait::async_trait] impl ConnectorIntegration for Stancer { @@ -199,6 +203,43 @@ impl ConnectorIntegration CustomResult<(), errors::ConnectorError> { + match ( + &router_data.request.payment_method_data, + &router_data.auth_type, + ) { + (api::PaymentMethodData::Card { .. }, enums::AuthenticationType::ThreeDs) => { + let types::RouterData { response, .. } = + services::execute_connector_processing_step( + app_state, + Box::new(self), + router_data, + payments::CallConnectorAction::Trigger, + None, + ) + .await?; + let response: types::PaymentsResponseData = response.map_err(|err| { + errors::ConnectorError::UnexpectedResponseError(err.message.into()) + })?; + + if let types::PaymentsResponseData::ThreeDSEnrollmentResponse { + enrolled_v2: three_ds_enrolled, + .. + } = response + { + router_data.request.enrolled_for_3ds = three_ds_enrolled; + } + } + _ => (), + } + + Ok(()) + } + fn get_request_body( &self, req: &types::PaymentsAuthorizeRouterData, diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 70f0ea6f2e2..4138f801ccf 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -192,10 +192,18 @@ impl TryFrom, ) -> Result { - let types::ResponseRouterData::<_, _, _, _> { response, .. } = item; + let types::ResponseRouterData::<_, _, _, _> { response, data, .. } = item; let Payment { status, auth, id, .. } = response; + let three_ds_response = auth.as_ref().and_then(|auth| { + matches!(auth.status, payment_auth::Status::Unavailable).then_some( + types::PaymentsResponseData::ThreeDSEnrollmentResponse { + enrolled_v2: false, + related_transaction_id: Some(id.to_owned()), + }, + ) + }); Ok(Self { status: status @@ -204,23 +212,27 @@ impl TryFrom Date: Thu, 18 Jan 2024 15:58:17 +0530 Subject: [PATCH 27/31] refactor: resolved conflicts and errors --- crates/api_models/src/enums.rs | 99 ------------ crates/common_enums/src/enums.rs | 1 + crates/connector_configs/src/connector.rs | 2 + crates/router/src/connector.rs | 6 +- crates/router/src/connector/stancer.rs | 68 +++----- crates/router/src/connector/stancer/models.rs | 153 ++++++++---------- .../src/connector/stancer/transformers.rs | 9 +- crates/router/src/core/payments/flows.rs | 9 ++ crates/router/tests/connectors/stancer.rs | 5 +- 9 files changed, 113 insertions(+), 239 deletions(-) diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 25a38efca98..31ee9ff33d6 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -152,105 +152,6 @@ impl Connector { } } -#[derive( - Clone, - Copy, - Debug, - Eq, - Hash, - PartialEq, - serde::Serialize, - serde::Deserialize, - strum::Display, - strum::EnumString, - strum::EnumIter, - strum::EnumVariantNames, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum RoutableConnectors { - #[cfg(feature = "dummy_connector")] - #[serde(rename = "phonypay")] - #[strum(serialize = "phonypay")] - DummyConnector1, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "fauxpay")] - #[strum(serialize = "fauxpay")] - DummyConnector2, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "pretendpay")] - #[strum(serialize = "pretendpay")] - DummyConnector3, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "stripe_test")] - #[strum(serialize = "stripe_test")] - DummyConnector4, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "adyen_test")] - #[strum(serialize = "adyen_test")] - DummyConnector5, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "checkout_test")] - #[strum(serialize = "checkout_test")] - DummyConnector6, - #[cfg(feature = "dummy_connector")] - #[serde(rename = "paypal_test")] - #[strum(serialize = "paypal_test")] - DummyConnector7, - Aci, - Adyen, - Airwallex, - Authorizedotnet, - Bankofamerica, - Bitpay, - Bambora, - Bluesnap, - Boku, - Braintree, - Cashtocode, - Checkout, - Coinbase, - Cryptopay, - Cybersource, - Dlocal, - Fiserv, - Forte, - Globalpay, - Globepay, - Gocardless, - Helcim, - Iatapay, - Klarna, - Mollie, - Multisafepay, - Nexinets, - Nmi, - Noon, - Nuvei, - // 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 - Payme, - Paypal, - Payu, - Powertranz, - Prophetpay, - Rapyd, - Shift4, - Square, - Stancer, - Stax, - Stripe, - Trustpay, - // Tsys, - Tsys, - Volt, - Wise, - Worldline, - Worldpay, - Zen, -} - #[cfg(feature = "payouts")] #[derive( Clone, diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 949cc2e0034..1be959f7c31 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -151,6 +151,7 @@ pub enum RoutableConnectors { Shift4, Signifyd, Square, + Stancer, Stax, Stripe, Trustpay, diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs index f0997d53107..6f3e6f70a7b 100644 --- a/crates/connector_configs/src/connector.rs +++ b/crates/connector_configs/src/connector.rs @@ -154,6 +154,7 @@ pub struct ConnectorConfig { pub worldpay: Option, pub zen: Option, pub square: Option, + pub stancer: Option, pub stax: Option, pub dummy_connector: Option, pub stripe_test: Option, @@ -246,6 +247,7 @@ impl ConnectorConfig { Connector::Shift4 => Ok(connector_data.shift4), Connector::Signifyd => Ok(connector_data.signifyd), Connector::Square => Ok(connector_data.square), + Connector::Stancer => Ok(connector_data.stancer), Connector::Stax => Ok(connector_data.stax), Connector::Stripe => Ok(connector_data.stripe), Connector::Trustpay => Ok(connector_data.trustpay), diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index eff3186c5f5..6f888d7df1f 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -68,7 +68,7 @@ pub use self::{ nexinets::Nexinets, nmi::Nmi, noon::Noon, nuvei::Nuvei, opayo::Opayo, opennode::Opennode, payeezy::Payeezy, payme::Payme, paypal::Paypal, payu::Payu, placetopay::Placetopay, powertranz::Powertranz, prophetpay::Prophetpay, rapyd::Rapyd, riskified::Riskified, - shift4::Shift4, signifyd::Signifyd, square::Square, stancer::Stancer, stax::Stax, stripe::Stripe, - trustpay::Trustpay, tsys::Tsys, volt::Volt, wise::Wise, - worldline::Worldline, worldpay::Worldpay, zen::Zen, + shift4::Shift4, signifyd::Signifyd, square::Square, stancer::Stancer, stax::Stax, + stripe::Stripe, trustpay::Trustpay, tsys::Tsys, volt::Volt, wise::Wise, worldline::Worldline, + worldpay::Worldpay, zen::Zen, }; diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 70ba543249d..b29f436b420 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -8,6 +8,11 @@ use error_stack::{IntoReport, ResultExt}; use masking::PeekInterface; use transformers as stancer; +use self::models::{ + CreateCustomerRequest, CreatePaymentRequest, CreateRefundRequest, Customer, Payment, Refund, + UpdatePaymentRequest, +}; +use super::utils::{PaymentsSyncRequestData, RefundsRequestData}; use crate::{ configs::settings, consts, @@ -25,18 +30,11 @@ use crate::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, storage::enums, - ErrorResponse, Response, + ErrorResponse, RequestContent, Response, }, - utils::{self, BytesExt}, -}; - -use self::models::{ - CreateCustomerRequest, CreatePaymentRequest, CreateRefundRequest, Customer, Payment, Refund, - UpdatePaymentRequest, + utils::BytesExt, }; -use super::utils::{PaymentsSyncRequestData, RefundsRequestData}; - #[derive(Debug, Clone)] pub struct Stancer; @@ -136,6 +134,7 @@ impl ConnectorCommon for Stancer { message: message.to_string(), reason: None, attempt_status: None, + connector_transaction_id: None, }) } } @@ -244,7 +243,7 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + ) -> CustomResult { let connector_router_data = stancer::StancerRouterData::try_from(( &self.get_currency_unit(), req.request.currency, @@ -252,12 +251,12 @@ impl ConnectorIntegration::encode_to_string_of_json, - ) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; - Ok(Some(stancer_req)) + // let stancer_req = types::RequestBody::log_and_get_request_body( + // &req_obj, + // utils::Encode::::encode_to_string_of_json, + // ) + // .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(RequestContent::Json(Box::new(req_obj))) } fn build_request( @@ -275,7 +274,7 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + ) -> CustomResult { let connector_router_data = stancer::StancerRouterData::try_from(( &self.get_currency_unit(), req.request.currency, @@ -413,12 +412,7 @@ impl ConnectorIntegration::encode_to_string_of_json, - ) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; - Ok(Some(stancer_req)) + Ok(RequestContent::Json(Box::new(req_obj))) } fn build_request( @@ -434,7 +428,7 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult { let connector_router_data = stancer::StancerRouterData::try_from(( &self.get_currency_unit(), req.request.currency, @@ -505,12 +499,7 @@ impl ConnectorIntegration::encode_to_string_of_json, - ) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; - Ok(Some(stancer_req)) + Ok(RequestContent::Json(Box::new(req_obj))) } fn build_request( @@ -525,7 +514,7 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + ) -> CustomResult { let connector_request = CreateCustomerRequest::try_from(req)?; - let stancer_req = types::RequestBody::log_and_get_request_body( - &connector_request, - utils::Encode::::url_encode, - ) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; - Ok(Some(stancer_req)) + Ok(RequestContent::Json(Box::new(connector_request))) } fn build_request( @@ -679,7 +663,7 @@ impl .headers(types::ConnectorCustomerType::get_headers( self, req, connectors, )?) - .body(types::ConnectorCustomerType::get_request_body( + .set_body(types::ConnectorCustomerType::get_request_body( self, req, connectors, )?) .build(); diff --git a/crates/router/src/connector/stancer/models.rs b/crates/router/src/connector/stancer/models.rs index f1eb59c8bc7..d743681f2f2 100644 --- a/crates/router/src/connector/stancer/models.rs +++ b/crates/router/src/connector/stancer/models.rs @@ -39,8 +39,8 @@ pub mod card { exp_month: i32, exp_year: i32, created: i32, - ) -> Card { - Card { + ) -> Self { + Self { id, last4, brand, @@ -72,7 +72,7 @@ pub mod card { Deferred, } impl Default for Funding { - fn default() -> Funding { + fn default() -> Self { Self::Credit } } @@ -86,7 +86,7 @@ pub mod card { Corporate, } impl Default for Nature { - fn default() -> Nature { + fn default() -> Self { Self::Personal } } @@ -100,7 +100,7 @@ pub mod card { Visa, } impl Default for Network { - fn default() -> Network { + fn default() -> Self { Self::National } } @@ -108,7 +108,7 @@ pub mod card { pub use self::card::Card; pub mod create_customer_request { use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct CreateCustomerRequest { #[serde(rename = "name", skip_serializing_if = "Option::is_none")] pub name: Option, @@ -162,8 +162,8 @@ pub mod create_payment_request { pub capture: Option, } impl CreatePaymentRequest { - pub fn new(amount: i32, currency: String) -> CreatePaymentRequest { - CreatePaymentRequest { + pub fn new(amount: i32, currency: String) -> Self { + Self { amount, currency, description: None, @@ -189,7 +189,7 @@ pub mod create_payment_request { Capture, } impl Default for Status { - fn default() -> Status { + fn default() -> Self { Self::Authorize } } @@ -201,7 +201,7 @@ pub mod create_payment_request { Sepa, } impl Default for MethodsAllowed { - fn default() -> MethodsAllowed { + fn default() -> Self { Self::Card } } @@ -215,8 +215,8 @@ pub mod create_payment_request_auth { pub return_url: String, } impl CreatePaymentRequestAuth { - pub fn new(return_url: String) -> CreatePaymentRequestAuth { - CreatePaymentRequestAuth { return_url } + pub fn new(return_url: String) -> Self { + Self { return_url } } } } @@ -240,8 +240,8 @@ pub mod create_payment_request_card { cvc: Secret, exp_year: Secret, exp_month: Secret, - ) -> CreatePaymentRequestCard { - CreatePaymentRequestCard { + ) -> Self { + Self { number, cvc, exp_year, @@ -267,8 +267,8 @@ pub mod create_payment_request_device { pub languages: Option, } impl CreatePaymentRequestDevice { - pub fn new(ip: String) -> CreatePaymentRequestDevice { - CreatePaymentRequestDevice { + pub fn new(ip: String) -> Self { + Self { ip, port: None, user_agent: None, @@ -289,8 +289,8 @@ pub mod create_refund_request { pub amount: i32, } impl CreateRefundRequest { - pub fn new(payment: String, amount: i32) -> CreateRefundRequest { - CreateRefundRequest { payment, amount } + pub fn new(payment: String, amount: i32) -> Self { + Self { payment, amount } } } } @@ -303,8 +303,8 @@ pub mod create_sepa_409_response { pub error: Box, } impl CreateSepa409Response { - pub fn new(error: CreateSepa409ResponseError) -> CreateSepa409Response { - CreateSepa409Response { + pub fn new(error: CreateSepa409ResponseError) -> Self { + Self { error: Box::new(error), } } @@ -321,11 +321,8 @@ pub mod create_sepa_409_response_error { pub r#type: String, } impl CreateSepa409ResponseError { - pub fn new( - message: CreateSepa409ResponseErrorMessage, - r#type: String, - ) -> CreateSepa409ResponseError { - CreateSepa409ResponseError { + pub fn new(message: CreateSepa409ResponseErrorMessage, r#type: String) -> Self { + Self { message: Box::new(message), r#type, } @@ -343,8 +340,8 @@ pub mod create_sepa_409_response_error_message { pub id: String, } impl CreateSepa409ResponseErrorMessage { - pub fn new(error: String, id: String) -> CreateSepa409ResponseErrorMessage { - CreateSepa409ResponseErrorMessage { error, id } + pub fn new(error: String, id: String) -> Self { + Self { error, id } } } } @@ -359,8 +356,8 @@ pub mod create_sepa_ibanonly_request { pub name: String, } impl CreateSepaIbanonlyRequest { - pub fn new(iban: String, name: String) -> CreateSepaIbanonlyRequest { - CreateSepaIbanonlyRequest { iban, name } + pub fn new(iban: String, name: String) -> Self { + Self { iban, name } } } } @@ -381,8 +378,8 @@ pub mod create_sepa_request { pub date_mandate: Option, } impl CreateSepaRequest { - pub fn new(name: String, iban: String) -> CreateSepaRequest { - CreateSepaRequest { + pub fn new(name: String, iban: String) -> Self { + Self { name, iban, bic: None, @@ -407,8 +404,8 @@ pub mod customer { pub mobile: Option, } impl Customer { - pub fn new(id: String) -> Customer { - Customer { + pub fn new(id: String) -> Self { + Self { id, name: None, email: None, @@ -447,8 +444,8 @@ pub mod dispute { date_bank: i32, payment: String, r#type: String, - ) -> Dispute { - Dispute { + ) -> Self { + Self { id, amount, created, @@ -472,11 +469,8 @@ pub mod get_disputes_200_response { pub range: Box, } impl GetDisputes200Response { - pub fn new( - disputes: Vec, - range: GetDisputes200ResponseRange, - ) -> GetDisputes200Response { - GetDisputes200Response { + pub fn new(disputes: Vec, range: GetDisputes200ResponseRange) -> Self { + Self { disputes, range: Box::new(range), } @@ -504,14 +498,8 @@ pub mod get_disputes_200_response_range { pub unique_id: Option, } impl GetDisputes200ResponseRange { - pub fn new( - created: i32, - start: i32, - end: i32, - limit: i32, - has_more: bool, - ) -> GetDisputes200ResponseRange { - GetDisputes200ResponseRange { + pub fn new(created: i32, start: i32, end: i32, limit: i32, has_more: bool) -> Self { + Self { created, start, end, @@ -532,8 +520,8 @@ pub mod get_disputes_404_response { pub error: Box, } impl GetDisputes404Response { - pub fn new(error: GetDisputes404ResponseError) -> GetDisputes404Response { - GetDisputes404Response { + pub fn new(error: GetDisputes404ResponseError) -> Self { + Self { error: Box::new(error), } } @@ -550,11 +538,8 @@ pub mod get_disputes_404_response_error { pub r#type: String, } impl GetDisputes404ResponseError { - pub fn new( - message: GetDisputes404ResponseErrorMessage, - r#type: String, - ) -> GetDisputes404ResponseError { - GetDisputes404ResponseError { + pub fn new(message: GetDisputes404ResponseErrorMessage, r#type: String) -> Self { + Self { message: Box::new(message), r#type, } @@ -570,8 +555,8 @@ pub mod get_disputes_404_response_error_message { pub id: String, } impl GetDisputes404ResponseErrorMessage { - pub fn new(id: String) -> GetDisputes404ResponseErrorMessage { - GetDisputes404ResponseErrorMessage { id } + pub fn new(id: String) -> Self { + Self { id } } } } @@ -592,8 +577,8 @@ pub mod list_payments_200_response { live_mode: bool, payments: Vec, range: ListPayments200ResponseRange, - ) -> ListPayments200Response { - ListPayments200Response { + ) -> Self { + Self { live_mode, payments, range: Box::new(range), @@ -622,14 +607,8 @@ pub mod list_payments_200_response_range { pub unique_id: Option, } impl ListPayments200ResponseRange { - pub fn new( - created: i32, - start: i32, - end: i32, - has_more: bool, - limit: i32, - ) -> ListPayments200ResponseRange { - ListPayments200ResponseRange { + pub fn new(created: i32, start: i32, end: i32, has_more: bool, limit: i32) -> Self { + Self { created, start, end, @@ -684,8 +663,8 @@ pub mod payment { pub customer: Option>, } impl Payment { - pub fn new(id: String, amount: i32, currency: String, created: i32) -> Payment { - Payment { + pub fn new(id: String, amount: i32, currency: String, created: i32) -> Self { + Self { id, amount, currency, @@ -715,7 +694,7 @@ pub mod payment { Card, } impl Default for Method { - fn default() -> Method { + fn default() -> Self { Self::Sepa } } @@ -741,7 +720,7 @@ pub mod payment { ToCapture, } impl Default for Status { - fn default() -> Status { + fn default() -> Self { Self::Authorized } } @@ -753,7 +732,7 @@ pub mod payment { Sepa, } impl Default for MethodsAllowed { - fn default() -> MethodsAllowed { + fn default() -> Self { Self::Card } } @@ -771,8 +750,8 @@ pub mod payment_auth { pub status: Status, } impl PaymentAuth { - pub fn new(redirect_url: String, return_url: String, status: Status) -> PaymentAuth { - PaymentAuth { + pub fn new(redirect_url: String, return_url: String, status: Status) -> Self { + Self { redirect_url, return_url, status, @@ -799,7 +778,7 @@ pub mod payment_auth { Unavailable, } impl Default for Status { - fn default() -> Status { + fn default() -> Self { Self::Attempted } } @@ -825,8 +804,8 @@ pub mod payment_device { pub country: Option, } impl PaymentDevice { - pub fn new(ip: String) -> PaymentDevice { - PaymentDevice { + pub fn new(ip: String) -> Self { + Self { ip, port: None, user_agent: None, @@ -870,8 +849,8 @@ pub mod refund { currency: String, status: Status, created: i32, - ) -> Refund { - Refund { + ) -> Self { + Self { id, payment, amount, @@ -898,7 +877,7 @@ pub mod refund { ToRefund, } impl Default for Status { - fn default() -> Status { + fn default() -> Self { Self::Failed } } @@ -926,8 +905,8 @@ pub mod sepa { pub date_mandate: Option, } impl Sepa { - pub fn new(id: String, name: String, created: i32, last4: String) -> Sepa { - Sepa { + pub fn new(id: String, name: String, created: i32, last4: String) -> Self { + Self { id, name, created, @@ -961,8 +940,8 @@ pub mod update_payment_request { pub status: Option, } impl UpdatePaymentRequest { - pub fn new() -> UpdatePaymentRequest { - UpdatePaymentRequest { + pub fn new() -> Self { + Self { amount: None, currency: None, order_id: None, @@ -981,7 +960,7 @@ pub mod update_payment_request { Capture, } impl Default for Status { - fn default() -> Status { + fn default() -> Self { Self::Authorize } } @@ -999,8 +978,8 @@ pub mod update_sepa_request { pub date_mandate: Option, } impl UpdateSepaRequest { - pub fn new() -> UpdateSepaRequest { - UpdateSepaRequest { + pub fn new() -> Self { + Self { name: None, mandate: None, date_mandate: None, diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 4138f801ccf..5cb76cc28cb 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -54,7 +54,7 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Create amount, router_data, } = item; - let request = CreatePaymentRequest { + let request = Self { description: router_data.description.to_owned(), order_id: Some(router_data.connector_request_reference_id.to_owned()), unique_id: Some(router_data.payment_id.to_owned()), @@ -67,7 +67,7 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Create }, ), customer: router_data.connector_customer.to_owned(), - ..CreatePaymentRequest::new( + ..Self::new( *amount, router_data.request.currency.to_string().to_lowercase(), ) @@ -78,7 +78,7 @@ impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for Create ); match &router_data.request.payment_method_data { - api::PaymentMethodData::Card(card) => Ok(CreatePaymentRequest { + api::PaymentMethodData::Card(card) => Ok(Self { card: Some( CreatePaymentRequestCard { number: card.card_number.to_owned(), @@ -135,7 +135,7 @@ impl TryFrom<&StancerRouterData<&types::PaymentsCaptureRouterData>> for UpdatePa Ok(Self { amount: Some(*amount), status: Some(update_payment_request::Status::Capture), - ..UpdatePaymentRequest::new() + ..Self::new() }) } } @@ -230,6 +230,7 @@ impl TryFrom Date: Thu, 18 Jan 2024 18:00:56 +0530 Subject: [PATCH 28/31] refactor: merged model.rs file in transformers.rs --- .typos.toml | 4 +- crates/router/src/connector/stancer.rs | 3 +- crates/router/src/connector/stancer/models.rs | 990 ---------------- .../src/connector/stancer/transformers.rs | 1019 ++++++++++++++++- 4 files changed, 1017 insertions(+), 999 deletions(-) delete mode 100644 crates/router/src/connector/stancer/models.rs diff --git a/.typos.toml b/.typos.toml index 4ce21526604..731de26384d 100644 --- a/.typos.toml +++ b/.typos.toml @@ -24,7 +24,9 @@ optin = "optin" # Boku preflow name optin_id = "optin_id" # Boku's id for optin flow deriver = "deriver" Deriver = "Deriver" -requestor_card_reference = "requestor_card_reference" +requestor_card_reference = "requestor_card_reference" +personnal = "personnal" #Stancer Nature +Personnal = "Personnal" #Stancer Nature [default.extend-words] aci = "aci" # Name of a connector diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index b29f436b420..55488d7b361 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -1,4 +1,3 @@ -pub mod models; pub mod transformers; use std::fmt::Debug; @@ -8,7 +7,7 @@ use error_stack::{IntoReport, ResultExt}; use masking::PeekInterface; use transformers as stancer; -use self::models::{ +use self::transformers::{ CreateCustomerRequest, CreatePaymentRequest, CreateRefundRequest, Customer, Payment, Refund, UpdatePaymentRequest, }; diff --git a/crates/router/src/connector/stancer/models.rs b/crates/router/src/connector/stancer/models.rs deleted file mode 100644 index d743681f2f2..00000000000 --- a/crates/router/src/connector/stancer/models.rs +++ /dev/null @@ -1,990 +0,0 @@ -use common_utils::pii::Email; -use masking::Secret; -use serde::{Deserialize, Serialize}; - -pub mod card { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct Card { - #[serde(rename = "id")] - pub id: String, - #[serde(rename = "last4")] - pub last4: String, - #[serde(rename = "brand")] - pub brand: String, - #[serde(rename = "exp_month")] - pub exp_month: i32, - #[serde(rename = "exp_year")] - pub exp_year: i32, - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "name", skip_serializing_if = "Option::is_none")] - pub name: Option, - #[serde(rename = "funding", skip_serializing_if = "Option::is_none")] - pub funding: Option, - #[serde(rename = "nature", skip_serializing_if = "Option::is_none")] - pub nature: Option, - #[serde(rename = "network", skip_serializing_if = "Option::is_none")] - pub network: Option, - #[serde(rename = "zip_code", skip_serializing_if = "Option::is_none")] - pub zip_code: Option, - #[serde(rename = "country", skip_serializing_if = "Option::is_none")] - pub country: Option, - } - impl Card { - pub fn new( - id: String, - last4: String, - brand: String, - exp_month: i32, - exp_year: i32, - created: i32, - ) -> Self { - Self { - id, - last4, - brand, - exp_month, - exp_year, - created, - name: None, - funding: None, - nature: None, - network: None, - zip_code: None, - country: None, - } - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Funding { - #[serde(rename = "credit")] - Credit, - #[serde(rename = "debit")] - Debit, - #[serde(rename = "prepaid")] - Prepaid, - #[serde(rename = "universal")] - Universal, - #[serde(rename = "charge")] - Charge, - #[serde(rename = "deferred")] - Deferred, - } - impl Default for Funding { - fn default() -> Self { - Self::Credit - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Nature { - #[serde(rename = "personal")] - Personal, - #[serde(rename = "personnal")] - Personnal, - #[serde(rename = "corporate")] - Corporate, - } - impl Default for Nature { - fn default() -> Self { - Self::Personal - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Network { - #[serde(rename = "national")] - National, - #[serde(rename = "mastercard")] - Mastercard, - #[serde(rename = "visa")] - Visa, - } - impl Default for Network { - fn default() -> Self { - Self::National - } - } -} -pub use self::card::Card; -pub mod create_customer_request { - use super::*; - #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateCustomerRequest { - #[serde(rename = "name", skip_serializing_if = "Option::is_none")] - pub name: Option, - #[serde(rename = "email", skip_serializing_if = "Option::is_none")] - pub email: Option, - #[serde(rename = "mobile", skip_serializing_if = "Option::is_none")] - pub mobile: Option>, - } - impl CreateCustomerRequest { - pub fn new() -> CreateCustomerRequest { - CreateCustomerRequest { - name: None, - email: None, - mobile: None, - } - } - } -} -pub use self::create_customer_request::CreateCustomerRequest; -pub mod create_payment_request { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreatePaymentRequest { - #[serde(rename = "amount")] - pub amount: i32, - #[serde(rename = "currency")] - pub currency: String, - #[serde(rename = "description", skip_serializing_if = "Option::is_none")] - pub description: Option, - #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] - pub order_id: Option, - #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] - pub unique_id: Option, - #[serde(rename = "customer", skip_serializing_if = "Option::is_none")] - pub customer: Option, - #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] - pub sepa: Option, - #[serde(rename = "card", skip_serializing_if = "Option::is_none")] - pub card: Option>, - #[serde(rename = "status", skip_serializing_if = "Option::is_none")] - pub status: Option, - #[serde(rename = "methods_allowed", skip_serializing_if = "Option::is_none")] - pub methods_allowed: Option>, - #[serde(rename = "return_url", skip_serializing_if = "Option::is_none")] - pub return_url: Option, - #[serde(rename = "auth", skip_serializing_if = "Option::is_none")] - pub auth: Option>, - #[serde(rename = "device", skip_serializing_if = "Option::is_none")] - pub device: Option>, - #[serde(rename = "capture", skip_serializing_if = "Option::is_none")] - pub capture: Option, - } - impl CreatePaymentRequest { - pub fn new(amount: i32, currency: String) -> Self { - Self { - amount, - currency, - description: None, - order_id: None, - unique_id: None, - customer: None, - sepa: None, - card: None, - status: None, - methods_allowed: None, - return_url: None, - auth: None, - device: None, - capture: None, - } - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Status { - #[serde(rename = "authorize")] - Authorize, - #[serde(rename = "capture")] - Capture, - } - impl Default for Status { - fn default() -> Self { - Self::Authorize - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum MethodsAllowed { - #[serde(rename = "card")] - Card, - #[serde(rename = "sepa")] - Sepa, - } - impl Default for MethodsAllowed { - fn default() -> Self { - Self::Card - } - } -} -pub use self::create_payment_request::CreatePaymentRequest; -pub mod create_payment_request_auth { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreatePaymentRequestAuth { - #[serde(rename = "return_url")] - pub return_url: String, - } - impl CreatePaymentRequestAuth { - pub fn new(return_url: String) -> Self { - Self { return_url } - } - } -} -pub use self::create_payment_request_auth::CreatePaymentRequestAuth; -pub mod create_payment_request_card { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreatePaymentRequestCard { - #[serde(rename = "number")] - pub number: cards::CardNumber, - #[serde(rename = "cvc")] - pub cvc: Secret, - #[serde(rename = "exp_year")] - pub exp_year: Secret, - #[serde(rename = "exp_month")] - pub exp_month: Secret, - } - impl CreatePaymentRequestCard { - pub fn new( - number: cards::CardNumber, - cvc: Secret, - exp_year: Secret, - exp_month: Secret, - ) -> Self { - Self { - number, - cvc, - exp_year, - exp_month, - } - } - } -} -pub use self::create_payment_request_card::CreatePaymentRequestCard; -pub mod create_payment_request_device { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreatePaymentRequestDevice { - #[serde(rename = "ip")] - pub ip: String, - #[serde(rename = "port", skip_serializing_if = "Option::is_none")] - pub port: Option, - #[serde(rename = "user_agent", skip_serializing_if = "Option::is_none")] - pub user_agent: Option, - #[serde(rename = "http_accept", skip_serializing_if = "Option::is_none")] - pub http_accept: Option, - #[serde(rename = "languages", skip_serializing_if = "Option::is_none")] - pub languages: Option, - } - impl CreatePaymentRequestDevice { - pub fn new(ip: String) -> Self { - Self { - ip, - port: None, - user_agent: None, - http_accept: None, - languages: None, - } - } - } -} -pub use self::create_payment_request_device::CreatePaymentRequestDevice; -pub mod create_refund_request { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateRefundRequest { - #[serde(rename = "payment")] - pub payment: String, - #[serde(rename = "amount")] - pub amount: i32, - } - impl CreateRefundRequest { - pub fn new(payment: String, amount: i32) -> Self { - Self { payment, amount } - } - } -} -pub use self::create_refund_request::CreateRefundRequest; -pub mod create_sepa_409_response { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateSepa409Response { - #[serde(rename = "error")] - pub error: Box, - } - impl CreateSepa409Response { - pub fn new(error: CreateSepa409ResponseError) -> Self { - Self { - error: Box::new(error), - } - } - } -} -pub use self::create_sepa_409_response::CreateSepa409Response; -pub mod create_sepa_409_response_error { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateSepa409ResponseError { - #[serde(rename = "message")] - pub message: Box, - #[serde(rename = "type")] - pub r#type: String, - } - impl CreateSepa409ResponseError { - pub fn new(message: CreateSepa409ResponseErrorMessage, r#type: String) -> Self { - Self { - message: Box::new(message), - r#type, - } - } - } -} -pub use self::create_sepa_409_response_error::CreateSepa409ResponseError; -pub mod create_sepa_409_response_error_message { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateSepa409ResponseErrorMessage { - #[serde(rename = "error")] - pub error: String, - #[serde(rename = "id")] - pub id: String, - } - impl CreateSepa409ResponseErrorMessage { - pub fn new(error: String, id: String) -> Self { - Self { error, id } - } - } -} -pub use self::create_sepa_409_response_error_message::CreateSepa409ResponseErrorMessage; -pub mod create_sepa_ibanonly_request { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateSepaIbanonlyRequest { - #[serde(rename = "iban")] - pub iban: String, - #[serde(rename = "name")] - pub name: String, - } - impl CreateSepaIbanonlyRequest { - pub fn new(iban: String, name: String) -> Self { - Self { iban, name } - } - } -} -pub use self::create_sepa_ibanonly_request::CreateSepaIbanonlyRequest; -pub mod create_sepa_request { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct CreateSepaRequest { - #[serde(rename = "name")] - pub name: String, - #[serde(rename = "iban")] - pub iban: String, - #[serde(rename = "bic", skip_serializing_if = "Option::is_none")] - pub bic: Option, - #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] - pub mandate: Option, - #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] - pub date_mandate: Option, - } - impl CreateSepaRequest { - pub fn new(name: String, iban: String) -> Self { - Self { - name, - iban, - bic: None, - mandate: None, - date_mandate: None, - } - } - } -} -pub use self::create_sepa_request::CreateSepaRequest; -pub mod customer { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct Customer { - #[serde(rename = "id")] - pub id: String, - #[serde(rename = "name", skip_serializing_if = "Option::is_none")] - pub name: Option, - #[serde(rename = "email", skip_serializing_if = "Option::is_none")] - pub email: Option, - #[serde(rename = "mobile", skip_serializing_if = "Option::is_none")] - pub mobile: Option, - } - impl Customer { - pub fn new(id: String) -> Self { - Self { - id, - name: None, - email: None, - mobile: None, - } - } - } -} -pub use self::customer::Customer; -pub mod dispute { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct Dispute { - #[serde(rename = "id")] - pub id: String, - #[serde(rename = "amount")] - pub amount: i32, - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "date_bank")] - pub date_bank: i32, - #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] - pub order_id: Option, - #[serde(rename = "payment")] - pub payment: String, - #[serde(rename = "response", skip_serializing_if = "Option::is_none")] - pub response: Option, - #[serde(rename = "type")] - pub r#type: String, - } - impl Dispute { - pub fn new( - id: String, - amount: i32, - created: i32, - date_bank: i32, - payment: String, - r#type: String, - ) -> Self { - Self { - id, - amount, - created, - date_bank, - order_id: None, - payment, - response: None, - r#type, - } - } - } -} -pub use self::dispute::Dispute; -pub mod get_disputes_200_response { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct GetDisputes200Response { - #[serde(rename = "disputes")] - pub disputes: Vec, - #[serde(rename = "range")] - pub range: Box, - } - impl GetDisputes200Response { - pub fn new(disputes: Vec, range: GetDisputes200ResponseRange) -> Self { - Self { - disputes, - range: Box::new(range), - } - } - } -} -pub use self::get_disputes_200_response::GetDisputes200Response; -pub mod get_disputes_200_response_range { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct GetDisputes200ResponseRange { - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "start")] - pub start: i32, - #[serde(rename = "end")] - pub end: i32, - #[serde(rename = "limit")] - pub limit: i32, - #[serde(rename = "has_more")] - pub has_more: bool, - #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] - pub order_id: Option, - #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] - pub unique_id: Option, - } - impl GetDisputes200ResponseRange { - pub fn new(created: i32, start: i32, end: i32, limit: i32, has_more: bool) -> Self { - Self { - created, - start, - end, - limit, - has_more, - order_id: None, - unique_id: None, - } - } - } -} -pub use self::get_disputes_200_response_range::GetDisputes200ResponseRange; -pub mod get_disputes_404_response { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct GetDisputes404Response { - #[serde(rename = "error")] - pub error: Box, - } - impl GetDisputes404Response { - pub fn new(error: GetDisputes404ResponseError) -> Self { - Self { - error: Box::new(error), - } - } - } -} -pub use self::get_disputes_404_response::GetDisputes404Response; -pub mod get_disputes_404_response_error { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct GetDisputes404ResponseError { - #[serde(rename = "message")] - pub message: Box, - #[serde(rename = "type")] - pub r#type: String, - } - impl GetDisputes404ResponseError { - pub fn new(message: GetDisputes404ResponseErrorMessage, r#type: String) -> Self { - Self { - message: Box::new(message), - r#type, - } - } - } -} -pub use self::get_disputes_404_response_error::GetDisputes404ResponseError; -pub mod get_disputes_404_response_error_message { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct GetDisputes404ResponseErrorMessage { - #[serde(rename = "id")] - pub id: String, - } - impl GetDisputes404ResponseErrorMessage { - pub fn new(id: String) -> Self { - Self { id } - } - } -} -pub use self::get_disputes_404_response_error_message::GetDisputes404ResponseErrorMessage; -pub mod list_payments_200_response { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct ListPayments200Response { - #[serde(rename = "live_mode")] - pub live_mode: bool, - #[serde(rename = "payments")] - pub payments: Vec, - #[serde(rename = "range")] - pub range: Box, - } - impl ListPayments200Response { - pub fn new( - live_mode: bool, - payments: Vec, - range: ListPayments200ResponseRange, - ) -> Self { - Self { - live_mode, - payments, - range: Box::new(range), - } - } - } -} -pub use self::list_payments_200_response::ListPayments200Response; -pub mod list_payments_200_response_range { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct ListPayments200ResponseRange { - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "start")] - pub start: i32, - #[serde(rename = "end")] - pub end: i32, - #[serde(rename = "has_more")] - pub has_more: bool, - #[serde(rename = "limit")] - pub limit: i32, - #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] - pub order_id: Option, - #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] - pub unique_id: Option, - } - impl ListPayments200ResponseRange { - pub fn new(created: i32, start: i32, end: i32, has_more: bool, limit: i32) -> Self { - Self { - created, - start, - end, - has_more, - limit, - order_id: None, - unique_id: None, - } - } - } -} -pub use self::list_payments_200_response_range::ListPayments200ResponseRange; -pub mod payment { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct Payment { - #[serde(rename = "id")] - pub id: String, - #[serde(rename = "amount")] - pub amount: i32, - #[serde(rename = "currency")] - pub currency: String, - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "fee", skip_serializing_if = "Option::is_none")] - pub fee: Option, - #[serde(rename = "description", skip_serializing_if = "Option::is_none")] - pub description: Option, - #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] - pub order_id: Option, - #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] - pub unique_id: Option, - #[serde(rename = "method", skip_serializing_if = "Option::is_none")] - pub method: Option, - #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] - pub sepa: Option>, - #[serde(rename = "card", skip_serializing_if = "Option::is_none")] - pub card: Option>, - #[serde(rename = "status", skip_serializing_if = "Option::is_none")] - pub status: Option, - #[serde(rename = "response", skip_serializing_if = "Option::is_none")] - pub response: Option, - #[serde(rename = "methods_allowed", skip_serializing_if = "Option::is_none")] - pub methods_allowed: Option>, - #[serde(rename = "return_url", skip_serializing_if = "Option::is_none")] - pub return_url: Option, - #[serde(rename = "auth", skip_serializing_if = "Option::is_none")] - pub auth: Option>, - #[serde(rename = "device", skip_serializing_if = "Option::is_none")] - pub device: Option>, - #[serde(rename = "customer", skip_serializing_if = "Option::is_none")] - pub customer: Option>, - } - impl Payment { - pub fn new(id: String, amount: i32, currency: String, created: i32) -> Self { - Self { - id, - amount, - currency, - created, - fee: None, - description: None, - order_id: None, - unique_id: None, - method: None, - sepa: None, - card: None, - status: None, - response: None, - methods_allowed: None, - return_url: None, - auth: None, - device: None, - customer: None, - } - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Method { - #[serde(rename = "sepa")] - Sepa, - #[serde(rename = "card")] - Card, - } - impl Default for Method { - fn default() -> Self { - Self::Sepa - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Status { - #[serde(rename = "authorized")] - Authorized, - #[serde(rename = "canceled")] - Canceled, - #[serde(rename = "captured")] - Captured, - #[serde(rename = "capture_sent")] - CaptureSent, - #[serde(rename = "disputed")] - Disputed, - #[serde(rename = "expired")] - Expired, - #[serde(rename = "failed")] - Failed, - #[serde(rename = "refused")] - Refused, - #[serde(rename = "to_capture")] - ToCapture, - } - impl Default for Status { - fn default() -> Self { - Self::Authorized - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum MethodsAllowed { - #[serde(rename = "card")] - Card, - #[serde(rename = "sepa")] - Sepa, - } - impl Default for MethodsAllowed { - fn default() -> Self { - Self::Card - } - } -} -pub use self::payment::Payment; -pub mod payment_auth { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct PaymentAuth { - #[serde(rename = "redirect_url")] - pub redirect_url: String, - #[serde(rename = "return_url")] - pub return_url: String, - #[serde(rename = "status")] - pub status: Status, - } - impl PaymentAuth { - pub fn new(redirect_url: String, return_url: String, status: Status) -> Self { - Self { - redirect_url, - return_url, - status, - } - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Status { - #[serde(rename = "attempted")] - Attempted, - #[serde(rename = "available")] - Available, - #[serde(rename = "declined")] - Declined, - #[serde(rename = "expired")] - Expired, - #[serde(rename = "failed")] - Failed, - #[serde(rename = "requested")] - Requested, - #[serde(rename = "success")] - Success, - #[serde(rename = "unavailable")] - Unavailable, - } - impl Default for Status { - fn default() -> Self { - Self::Attempted - } - } -} -pub use self::payment_auth::PaymentAuth; -pub mod payment_device { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct PaymentDevice { - #[serde(rename = "ip")] - pub ip: String, - #[serde(rename = "port", skip_serializing_if = "Option::is_none")] - pub port: Option, - #[serde(rename = "user_agent", skip_serializing_if = "Option::is_none")] - pub user_agent: Option, - #[serde(rename = "http_accept", skip_serializing_if = "Option::is_none")] - pub http_accept: Option, - #[serde(rename = "languages", skip_serializing_if = "Option::is_none")] - pub languages: Option, - #[serde(rename = "city", skip_serializing_if = "Option::is_none")] - pub city: Option, - #[serde(rename = "country", skip_serializing_if = "Option::is_none")] - pub country: Option, - } - impl PaymentDevice { - pub fn new(ip: String) -> Self { - Self { - ip, - port: None, - user_agent: None, - http_accept: None, - languages: None, - city: None, - country: None, - } - } - } -} -pub use self::payment_device::PaymentDevice; -pub mod refund { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct Refund { - #[serde(rename = "id")] - pub id: String, - #[serde(rename = "payment")] - pub payment: String, - #[serde(rename = "amount")] - pub amount: i32, - #[serde(rename = "currency")] - pub currency: String, - #[serde(rename = "status")] - pub status: Status, - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "date_refund", skip_serializing_if = "Option::is_none")] - pub date_refund: Option, - #[serde(rename = "date_bank", skip_serializing_if = "Option::is_none")] - pub date_bank: Option, - #[serde(rename = "live_mode", skip_serializing_if = "Option::is_none")] - pub live_mode: Option, - } - impl Refund { - pub fn new( - id: String, - payment: String, - amount: i32, - currency: String, - status: Status, - created: i32, - ) -> Self { - Self { - id, - payment, - amount, - currency, - status, - created, - date_refund: None, - date_bank: None, - live_mode: None, - } - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Status { - #[serde(rename = "failed")] - Failed, - #[serde(rename = "not_honored")] - NotHonored, - #[serde(rename = "refund_sent")] - RefundSent, - #[serde(rename = "refunded")] - Refunded, - #[serde(rename = "to_refund")] - ToRefund, - } - impl Default for Status { - fn default() -> Self { - Self::Failed - } - } -} -pub use self::refund::Refund; -pub mod sepa { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct Sepa { - #[serde(rename = "id")] - pub id: String, - #[serde(rename = "name")] - pub name: String, - #[serde(rename = "created")] - pub created: i32, - #[serde(rename = "last4")] - pub last4: String, - #[serde(rename = "bic", skip_serializing_if = "Option::is_none")] - pub bic: Option, - #[serde(rename = "live_mode", skip_serializing_if = "Option::is_none")] - pub live_mode: Option, - #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] - pub mandate: Option, - #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] - pub date_mandate: Option, - } - impl Sepa { - pub fn new(id: String, name: String, created: i32, last4: String) -> Self { - Self { - id, - name, - created, - last4, - bic: None, - live_mode: None, - mandate: None, - date_mandate: None, - } - } - } -} -pub use self::sepa::Sepa; -pub mod update_payment_request { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct UpdatePaymentRequest { - #[serde(rename = "amount", skip_serializing_if = "Option::is_none")] - pub amount: Option, - #[serde(rename = "currency", skip_serializing_if = "Option::is_none")] - pub currency: Option, - #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] - pub order_id: Option, - #[serde(rename = "description", skip_serializing_if = "Option::is_none")] - pub description: Option, - #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] - pub sepa: Option, - #[serde(rename = "card", skip_serializing_if = "Option::is_none")] - pub card: Option, - #[serde(rename = "status", skip_serializing_if = "Option::is_none")] - pub status: Option, - } - impl UpdatePaymentRequest { - pub fn new() -> Self { - Self { - amount: None, - currency: None, - order_id: None, - description: None, - sepa: None, - card: None, - status: None, - } - } - } - #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] - pub enum Status { - #[serde(rename = "authorize")] - Authorize, - #[serde(rename = "capture")] - Capture, - } - impl Default for Status { - fn default() -> Self { - Self::Authorize - } - } -} -pub use self::update_payment_request::UpdatePaymentRequest; -pub mod update_sepa_request { - use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] - pub struct UpdateSepaRequest { - #[serde(rename = "name", skip_serializing_if = "Option::is_none")] - pub name: Option, - #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] - pub mandate: Option, - #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] - pub date_mandate: Option, - } - impl UpdateSepaRequest { - pub fn new() -> Self { - Self { - name: None, - mandate: None, - date_mandate: None, - } - } - } -} -pub use self::update_sepa_request::UpdateSepaRequest; diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index 5cb76cc28cb..e87ee8424a0 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -1,12 +1,7 @@ +use common_utils::pii::Email; use masking::Secret; use serde::{Deserialize, Serialize}; -use super::models::{ - payment, payment_auth, refund, update_payment_request, CreateCustomerRequest, - CreatePaymentRequest, CreatePaymentRequestAuth, CreatePaymentRequestCard, - CreatePaymentRequestDevice, CreateRefundRequest, Customer, Payment, Refund, - UpdatePaymentRequest, -}; use crate::{ core::errors, services, @@ -44,6 +39,757 @@ impl } } +pub mod card { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Card { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "last4")] + pub last4: String, + #[serde(rename = "brand")] + pub brand: String, + #[serde(rename = "exp_month")] + pub exp_month: i32, + #[serde(rename = "exp_year")] + pub exp_year: i32, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "funding", skip_serializing_if = "Option::is_none")] + pub funding: Option, + #[serde(rename = "nature", skip_serializing_if = "Option::is_none")] + pub nature: Option, + #[serde(rename = "network", skip_serializing_if = "Option::is_none")] + pub network: Option, + #[serde(rename = "zip_code", skip_serializing_if = "Option::is_none")] + pub zip_code: Option, + #[serde(rename = "country", skip_serializing_if = "Option::is_none")] + pub country: Option, + } + impl Card { + pub fn new( + id: String, + last4: String, + brand: String, + exp_month: i32, + exp_year: i32, + created: i32, + ) -> Self { + Self { + id, + last4, + brand, + exp_month, + exp_year, + created, + name: None, + funding: None, + nature: None, + network: None, + zip_code: None, + country: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Funding { + #[serde(rename = "credit")] + Credit, + #[serde(rename = "debit")] + Debit, + #[serde(rename = "prepaid")] + Prepaid, + #[serde(rename = "universal")] + Universal, + #[serde(rename = "charge")] + Charge, + #[serde(rename = "deferred")] + Deferred, + } + impl Default for Funding { + fn default() -> Self { + Self::Credit + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Nature { + #[serde(rename = "personal")] + Personal, + #[serde(rename = "personnal")] + Personnal, + #[serde(rename = "corporate")] + Corporate, + } + impl Default for Nature { + fn default() -> Self { + Self::Personal + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Network { + #[serde(rename = "national")] + National, + #[serde(rename = "mastercard")] + Mastercard, + #[serde(rename = "visa")] + Visa, + } + impl Default for Network { + fn default() -> Self { + Self::National + } + } +} + +pub use self::create_payment_request_auth::CreatePaymentRequestAuth; +pub mod create_payment_request_card { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequestCard { + #[serde(rename = "number")] + pub number: cards::CardNumber, + #[serde(rename = "cvc")] + pub cvc: Secret, + #[serde(rename = "exp_year")] + pub exp_year: Secret, + #[serde(rename = "exp_month")] + pub exp_month: Secret, + } + impl CreatePaymentRequestCard { + pub fn new( + number: cards::CardNumber, + cvc: Secret, + exp_year: Secret, + exp_month: Secret, + ) -> Self { + Self { + number, + cvc, + exp_year, + exp_month, + } + } + } +} + +pub use self::create_payment_request_card::CreatePaymentRequestCard; +pub mod create_payment_request_device { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequestDevice { + #[serde(rename = "ip")] + pub ip: String, + #[serde(rename = "port", skip_serializing_if = "Option::is_none")] + pub port: Option, + #[serde(rename = "user_agent", skip_serializing_if = "Option::is_none")] + pub user_agent: Option, + #[serde(rename = "http_accept", skip_serializing_if = "Option::is_none")] + pub http_accept: Option, + #[serde(rename = "languages", skip_serializing_if = "Option::is_none")] + pub languages: Option, + } + impl CreatePaymentRequestDevice { + pub fn new(ip: String) -> Self { + Self { + ip, + port: None, + user_agent: None, + http_accept: None, + languages: None, + } + } + } +} + +pub use self::customer::Customer; +pub mod dispute { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Dispute { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "date_bank")] + pub date_bank: i32, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "payment")] + pub payment: String, + #[serde(rename = "response", skip_serializing_if = "Option::is_none")] + pub response: Option, + #[serde(rename = "type")] + pub r#type: String, + } + impl Dispute { + pub fn new( + id: String, + amount: i32, + created: i32, + date_bank: i32, + payment: String, + r#type: String, + ) -> Self { + Self { + id, + amount, + created, + date_bank, + order_id: None, + payment, + response: None, + r#type, + } + } + } +} + +pub use self::dispute::Dispute; +pub mod get_disputes_200_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes200Response { + #[serde(rename = "disputes")] + pub disputes: Vec, + #[serde(rename = "range")] + pub range: Box, + } + impl GetDisputes200Response { + pub fn new(disputes: Vec, range: GetDisputes200ResponseRange) -> Self { + Self { + disputes, + range: Box::new(range), + } + } + } +} + +pub use self::get_disputes_200_response::GetDisputes200Response; +pub mod get_disputes_200_response_range { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes200ResponseRange { + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "start")] + pub start: i32, + #[serde(rename = "end")] + pub end: i32, + #[serde(rename = "limit")] + pub limit: i32, + #[serde(rename = "has_more")] + pub has_more: bool, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + } + impl GetDisputes200ResponseRange { + pub fn new(created: i32, start: i32, end: i32, limit: i32, has_more: bool) -> Self { + Self { + created, + start, + end, + limit, + has_more, + order_id: None, + unique_id: None, + } + } + } +} + +pub use self::get_disputes_200_response_range::GetDisputes200ResponseRange; +pub mod get_disputes_404_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes404Response { + #[serde(rename = "error")] + pub error: Box, + } + impl GetDisputes404Response { + pub fn new(error: GetDisputes404ResponseError) -> Self { + Self { + error: Box::new(error), + } + } + } +} + +pub use self::get_disputes_404_response::GetDisputes404Response; +pub mod get_disputes_404_response_error { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes404ResponseError { + #[serde(rename = "message")] + pub message: Box, + #[serde(rename = "type")] + pub r#type: String, + } + impl GetDisputes404ResponseError { + pub fn new(message: GetDisputes404ResponseErrorMessage, r#type: String) -> Self { + Self { + message: Box::new(message), + r#type, + } + } + } +} +pub use self::get_disputes_404_response_error::GetDisputes404ResponseError; +pub mod get_disputes_404_response_error_message { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct GetDisputes404ResponseErrorMessage { + #[serde(rename = "id")] + pub id: String, + } + impl GetDisputes404ResponseErrorMessage { + pub fn new(id: String) -> Self { + Self { id } + } + } +} + +pub use self::get_disputes_404_response_error_message::GetDisputes404ResponseErrorMessage; +pub mod list_payments_200_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct ListPayments200Response { + #[serde(rename = "live_mode")] + pub live_mode: bool, + #[serde(rename = "payments")] + pub payments: Vec, + #[serde(rename = "range")] + pub range: Box, + } + impl ListPayments200Response { + pub fn new( + live_mode: bool, + payments: Vec, + range: ListPayments200ResponseRange, + ) -> Self { + Self { + live_mode, + payments, + range: Box::new(range), + } + } + } +} +pub use self::list_payments_200_response::ListPayments200Response; +pub mod list_payments_200_response_range { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct ListPayments200ResponseRange { + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "start")] + pub start: i32, + #[serde(rename = "end")] + pub end: i32, + #[serde(rename = "has_more")] + pub has_more: bool, + #[serde(rename = "limit")] + pub limit: i32, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + } + impl ListPayments200ResponseRange { + pub fn new(created: i32, start: i32, end: i32, has_more: bool, limit: i32) -> Self { + Self { + created, + start, + end, + has_more, + limit, + order_id: None, + unique_id: None, + } + } + } +} + +pub use self::list_payments_200_response_range::ListPayments200ResponseRange; +pub mod payment { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Payment { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "currency")] + pub currency: String, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "fee", skip_serializing_if = "Option::is_none")] + pub fee: Option, + #[serde(rename = "description", skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + #[serde(rename = "method", skip_serializing_if = "Option::is_none")] + pub method: Option, + #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] + pub sepa: Option>, + #[serde(rename = "card", skip_serializing_if = "Option::is_none")] + pub card: Option>, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(rename = "response", skip_serializing_if = "Option::is_none")] + pub response: Option, + #[serde(rename = "methods_allowed", skip_serializing_if = "Option::is_none")] + pub methods_allowed: Option>, + #[serde(rename = "return_url", skip_serializing_if = "Option::is_none")] + pub return_url: Option, + #[serde(rename = "auth", skip_serializing_if = "Option::is_none")] + pub auth: Option>, + #[serde(rename = "device", skip_serializing_if = "Option::is_none")] + pub device: Option>, + #[serde(rename = "customer", skip_serializing_if = "Option::is_none")] + pub customer: Option>, + } + impl Payment { + pub fn new(id: String, amount: i32, currency: String, created: i32) -> Self { + Self { + id, + amount, + currency, + created, + fee: None, + description: None, + order_id: None, + unique_id: None, + method: None, + sepa: None, + card: None, + status: None, + response: None, + methods_allowed: None, + return_url: None, + auth: None, + device: None, + customer: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Method { + #[serde(rename = "sepa")] + Sepa, + #[serde(rename = "card")] + Card, + } + impl Default for Method { + fn default() -> Self { + Self::Sepa + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "authorized")] + Authorized, + #[serde(rename = "canceled")] + Canceled, + #[serde(rename = "captured")] + Captured, + #[serde(rename = "capture_sent")] + CaptureSent, + #[serde(rename = "disputed")] + Disputed, + #[serde(rename = "expired")] + Expired, + #[serde(rename = "failed")] + Failed, + #[serde(rename = "refused")] + Refused, + #[serde(rename = "to_capture")] + ToCapture, + } + impl Default for Status { + fn default() -> Self { + Self::Authorized + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum MethodsAllowed { + #[serde(rename = "card")] + Card, + #[serde(rename = "sepa")] + Sepa, + } + impl Default for MethodsAllowed { + fn default() -> Self { + Self::Card + } + } +} + +pub use self::payment::Payment; +pub mod payment_auth { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct PaymentAuth { + #[serde(rename = "redirect_url")] + pub redirect_url: String, + #[serde(rename = "return_url")] + pub return_url: String, + #[serde(rename = "status")] + pub status: Status, + } + impl PaymentAuth { + pub fn new(redirect_url: String, return_url: String, status: Status) -> Self { + Self { + redirect_url, + return_url, + status, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "attempted")] + Attempted, + #[serde(rename = "available")] + Available, + #[serde(rename = "declined")] + Declined, + #[serde(rename = "expired")] + Expired, + #[serde(rename = "failed")] + Failed, + #[serde(rename = "requested")] + Requested, + #[serde(rename = "success")] + Success, + #[serde(rename = "unavailable")] + Unavailable, + } + impl Default for Status { + fn default() -> Self { + Self::Attempted + } + } +} + +pub use self::payment_auth::PaymentAuth; +pub mod payment_device { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct PaymentDevice { + #[serde(rename = "ip")] + pub ip: String, + #[serde(rename = "port", skip_serializing_if = "Option::is_none")] + pub port: Option, + #[serde(rename = "user_agent", skip_serializing_if = "Option::is_none")] + pub user_agent: Option, + #[serde(rename = "http_accept", skip_serializing_if = "Option::is_none")] + pub http_accept: Option, + #[serde(rename = "languages", skip_serializing_if = "Option::is_none")] + pub languages: Option, + #[serde(rename = "city", skip_serializing_if = "Option::is_none")] + pub city: Option, + #[serde(rename = "country", skip_serializing_if = "Option::is_none")] + pub country: Option, + } + impl PaymentDevice { + pub fn new(ip: String) -> Self { + Self { + ip, + port: None, + user_agent: None, + http_accept: None, + languages: None, + city: None, + country: None, + } + } + } +} + +pub use self::payment_device::PaymentDevice; +pub mod refund { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Refund { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "payment")] + pub payment: String, + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "currency")] + pub currency: String, + #[serde(rename = "status")] + pub status: Status, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "date_refund", skip_serializing_if = "Option::is_none")] + pub date_refund: Option, + #[serde(rename = "date_bank", skip_serializing_if = "Option::is_none")] + pub date_bank: Option, + #[serde(rename = "live_mode", skip_serializing_if = "Option::is_none")] + pub live_mode: Option, + } + impl Refund { + pub fn new( + id: String, + payment: String, + amount: i32, + currency: String, + status: Status, + created: i32, + ) -> Self { + Self { + id, + payment, + amount, + currency, + status, + created, + date_refund: None, + date_bank: None, + live_mode: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "failed")] + Failed, + #[serde(rename = "not_honored")] + NotHonored, + #[serde(rename = "refund_sent")] + RefundSent, + #[serde(rename = "refunded")] + Refunded, + #[serde(rename = "to_refund")] + ToRefund, + } + impl Default for Status { + fn default() -> Self { + Self::Failed + } + } +} + +pub use self::refund::Refund; +pub mod sepa { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Sepa { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "created")] + pub created: i32, + #[serde(rename = "last4")] + pub last4: String, + #[serde(rename = "bic", skip_serializing_if = "Option::is_none")] + pub bic: Option, + #[serde(rename = "live_mode", skip_serializing_if = "Option::is_none")] + pub live_mode: Option, + #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] + pub mandate: Option, + #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] + pub date_mandate: Option, + } + impl Sepa { + pub fn new(id: String, name: String, created: i32, last4: String) -> Self { + Self { + id, + name, + created, + last4, + bic: None, + live_mode: None, + mandate: None, + date_mandate: None, + } + } + } +} + +pub use self::sepa::Sepa; +pub mod update_payment_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct UpdatePaymentRequest { + #[serde(rename = "amount", skip_serializing_if = "Option::is_none")] + pub amount: Option, + #[serde(rename = "currency", skip_serializing_if = "Option::is_none")] + pub currency: Option, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "description", skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] + pub sepa: Option, + #[serde(rename = "card", skip_serializing_if = "Option::is_none")] + pub card: Option, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + } + impl UpdatePaymentRequest { + pub fn new() -> Self { + Self { + amount: None, + currency: None, + order_id: None, + description: None, + sepa: None, + card: None, + status: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "authorize")] + Authorize, + #[serde(rename = "capture")] + Capture, + } + impl Default for Status { + fn default() -> Self { + Self::Authorize + } + } +} + +pub use self::update_payment_request::UpdatePaymentRequest; +pub mod update_sepa_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct UpdateSepaRequest { + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] + pub mandate: Option, + #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] + pub date_mandate: Option, + } + impl UpdateSepaRequest { + pub fn new() -> Self { + Self { + name: None, + mandate: None, + date_mandate: None, + } + } + } +} +pub use self::update_sepa_request::UpdateSepaRequest; + // CreatePaymentRequest impl TryFrom<&StancerRouterData<&types::PaymentsAuthorizeRouterData>> for CreatePaymentRequest { type Error = error_stack::Report; @@ -238,6 +984,149 @@ impl TryFrom Self { + Self { payment, amount } + } + } +} + +pub use self::create_refund_request::CreateRefundRequest; +pub mod create_sepa_409_response { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepa409Response { + #[serde(rename = "error")] + pub error: Box, + } + impl CreateSepa409Response { + pub fn new(error: CreateSepa409ResponseError) -> Self { + Self { + error: Box::new(error), + } + } + } +} + +pub use self::create_sepa_409_response::CreateSepa409Response; +pub mod create_sepa_409_response_error { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepa409ResponseError { + #[serde(rename = "message")] + pub message: Box, + #[serde(rename = "type")] + pub r#type: String, + } + impl CreateSepa409ResponseError { + pub fn new(message: CreateSepa409ResponseErrorMessage, r#type: String) -> Self { + Self { + message: Box::new(message), + r#type, + } + } + } +} + +pub use self::create_sepa_409_response_error::CreateSepa409ResponseError; +pub mod create_sepa_409_response_error_message { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepa409ResponseErrorMessage { + #[serde(rename = "error")] + pub error: String, + #[serde(rename = "id")] + pub id: String, + } + impl CreateSepa409ResponseErrorMessage { + pub fn new(error: String, id: String) -> Self { + Self { error, id } + } + } +} + +pub use self::create_sepa_409_response_error_message::CreateSepa409ResponseErrorMessage; +pub mod create_sepa_ibanonly_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepaIbanonlyRequest { + #[serde(rename = "iban")] + pub iban: String, + #[serde(rename = "name")] + pub name: String, + } + impl CreateSepaIbanonlyRequest { + pub fn new(iban: String, name: String) -> Self { + Self { iban, name } + } + } +} + +pub use self::create_sepa_ibanonly_request::CreateSepaIbanonlyRequest; +pub mod create_sepa_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateSepaRequest { + #[serde(rename = "name")] + pub name: String, + #[serde(rename = "iban")] + pub iban: String, + #[serde(rename = "bic", skip_serializing_if = "Option::is_none")] + pub bic: Option, + #[serde(rename = "mandate", skip_serializing_if = "Option::is_none")] + pub mandate: Option, + #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] + pub date_mandate: Option, + } + impl CreateSepaRequest { + pub fn new(name: String, iban: String) -> Self { + Self { + name, + iban, + bic: None, + mandate: None, + date_mandate: None, + } + } + } +} + +pub use self::create_sepa_request::CreateSepaRequest; +pub mod customer { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct Customer { + #[serde(rename = "id")] + pub id: String, + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "email", skip_serializing_if = "Option::is_none")] + pub email: Option, + #[serde(rename = "mobile", skip_serializing_if = "Option::is_none")] + pub mobile: Option, + } + impl Customer { + pub fn new(id: String) -> Self { + Self { + id, + name: None, + email: None, + mobile: None, + } + } + } +} + // CreateRefundRequest impl TryFrom<&StancerRouterData<&types::RefundsRouterData>> for CreateRefundRequest { type Error = error_stack::Report; @@ -301,6 +1190,124 @@ impl TryFrom> } } +pub use self::card::Card; +pub mod create_customer_request { + use super::*; + #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreateCustomerRequest { + #[serde(rename = "name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "email", skip_serializing_if = "Option::is_none")] + pub email: Option, + #[serde(rename = "mobile", skip_serializing_if = "Option::is_none")] + pub mobile: Option>, + } + impl CreateCustomerRequest { + pub fn new() -> Self { + Self { + name: None, + email: None, + mobile: None, + } + } + } +} + +pub use self::create_customer_request::CreateCustomerRequest; +pub mod create_payment_request { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequest { + #[serde(rename = "amount")] + pub amount: i32, + #[serde(rename = "currency")] + pub currency: String, + #[serde(rename = "description", skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(rename = "order_id", skip_serializing_if = "Option::is_none")] + pub order_id: Option, + #[serde(rename = "unique_id", skip_serializing_if = "Option::is_none")] + pub unique_id: Option, + #[serde(rename = "customer", skip_serializing_if = "Option::is_none")] + pub customer: Option, + #[serde(rename = "sepa", skip_serializing_if = "Option::is_none")] + pub sepa: Option, + #[serde(rename = "card", skip_serializing_if = "Option::is_none")] + pub card: Option>, + #[serde(rename = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde(rename = "methods_allowed", skip_serializing_if = "Option::is_none")] + pub methods_allowed: Option>, + #[serde(rename = "return_url", skip_serializing_if = "Option::is_none")] + pub return_url: Option, + #[serde(rename = "auth", skip_serializing_if = "Option::is_none")] + pub auth: Option>, + #[serde(rename = "device", skip_serializing_if = "Option::is_none")] + pub device: Option>, + #[serde(rename = "capture", skip_serializing_if = "Option::is_none")] + pub capture: Option, + } + impl CreatePaymentRequest { + pub fn new(amount: i32, currency: String) -> Self { + Self { + amount, + currency, + description: None, + order_id: None, + unique_id: None, + customer: None, + sepa: None, + card: None, + status: None, + methods_allowed: None, + return_url: None, + auth: None, + device: None, + capture: None, + } + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum Status { + #[serde(rename = "authorize")] + Authorize, + #[serde(rename = "capture")] + Capture, + } + impl Default for Status { + fn default() -> Self { + Self::Authorize + } + } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + pub enum MethodsAllowed { + #[serde(rename = "card")] + Card, + #[serde(rename = "sepa")] + Sepa, + } + impl Default for MethodsAllowed { + fn default() -> Self { + Self::Card + } + } +} + +pub use self::create_payment_request::CreatePaymentRequest; +pub mod create_payment_request_auth { + use super::*; + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + pub struct CreatePaymentRequestAuth { + #[serde(rename = "return_url")] + pub return_url: String, + } + impl CreatePaymentRequestAuth { + pub fn new(return_url: String) -> Self { + Self { return_url } + } + } +} + // CreateCustomerRequest impl TryFrom<&types::ConnectorCustomerRouterData> for CreateCustomerRequest { type Error = error_stack::Report; From 64017e2f29f31da1dd5015c93c1568e856908c3a Mon Sep 17 00:00:00 2001 From: swangi-kumari Date: Thu, 18 Jan 2024 18:51:05 +0530 Subject: [PATCH 29/31] refactor: resolve clippy warnings and openspecs --- crates/router/src/connector/stancer.rs | 47 ++++++++----------- .../src/connector/stancer/transformers.rs | 29 ++---------- openapi/openapi_spec.json | 1 + 3 files changed, 24 insertions(+), 53 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index 55488d7b361..c81a19e65dc 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -206,33 +206,29 @@ impl ConnectorIntegration CustomResult<(), errors::ConnectorError> { - match ( + if let (api::PaymentMethodData::Card { .. }, enums::AuthenticationType::ThreeDs) = ( &router_data.request.payment_method_data, &router_data.auth_type, ) { - (api::PaymentMethodData::Card { .. }, enums::AuthenticationType::ThreeDs) => { - let types::RouterData { response, .. } = - services::execute_connector_processing_step( - app_state, - Box::new(self), - router_data, - payments::CallConnectorAction::Trigger, - None, - ) - .await?; - let response: types::PaymentsResponseData = response.map_err(|err| { - errors::ConnectorError::UnexpectedResponseError(err.message.into()) - })?; - - if let types::PaymentsResponseData::ThreeDSEnrollmentResponse { - enrolled_v2: three_ds_enrolled, - .. - } = response - { - router_data.request.enrolled_for_3ds = three_ds_enrolled; - } + let types::RouterData { response, .. } = services::execute_connector_processing_step( + app_state, + Box::new(self), + router_data, + payments::CallConnectorAction::Trigger, + None, + ) + .await?; + let response: types::PaymentsResponseData = response.map_err(|err| { + errors::ConnectorError::UnexpectedResponseError(err.message.into()) + })?; + + if let types::PaymentsResponseData::ThreeDSEnrollmentResponse { + enrolled_v2: three_ds_enrolled, + .. + } = response + { + router_data.request.enrolled_for_3ds = three_ds_enrolled; } - _ => (), } Ok(()) @@ -250,11 +246,6 @@ impl ConnectorIntegration::encode_to_string_of_json, - // ) - // .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(RequestContent::Json(Box::new(req_obj))) } diff --git a/crates/router/src/connector/stancer/transformers.rs b/crates/router/src/connector/stancer/transformers.rs index e87ee8424a0..c357316ef44 100644 --- a/crates/router/src/connector/stancer/transformers.rs +++ b/crates/router/src/connector/stancer/transformers.rs @@ -722,7 +722,7 @@ pub mod sepa { pub use self::sepa::Sepa; pub mod update_payment_request { use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct UpdatePaymentRequest { #[serde(rename = "amount", skip_serializing_if = "Option::is_none")] pub amount: Option, @@ -739,19 +739,7 @@ pub mod update_payment_request { #[serde(rename = "status", skip_serializing_if = "Option::is_none")] pub status: Option, } - impl UpdatePaymentRequest { - pub fn new() -> Self { - Self { - amount: None, - currency: None, - order_id: None, - description: None, - sepa: None, - card: None, - status: None, - } - } - } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Status { #[serde(rename = "authorize")] @@ -769,7 +757,7 @@ pub mod update_payment_request { pub use self::update_payment_request::UpdatePaymentRequest; pub mod update_sepa_request { use super::*; - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct UpdateSepaRequest { #[serde(rename = "name", skip_serializing_if = "Option::is_none")] pub name: Option, @@ -778,15 +766,6 @@ pub mod update_sepa_request { #[serde(rename = "date_mandate", skip_serializing_if = "Option::is_none")] pub date_mandate: Option, } - impl UpdateSepaRequest { - pub fn new() -> Self { - Self { - name: None, - mandate: None, - date_mandate: None, - } - } - } } pub use self::update_sepa_request::UpdateSepaRequest; @@ -881,7 +860,7 @@ impl TryFrom<&StancerRouterData<&types::PaymentsCaptureRouterData>> for UpdatePa Ok(Self { amount: Some(*amount), status: Some(update_payment_request::Status::Capture), - ..Self::new() + ..Self::default() }) } } diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index b2f5d3ea52c..912d5462055 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -4600,6 +4600,7 @@ "rapyd", "shift4", "square", + "stancer", "stax", "stripe", "trustpay", From e13ce0f65e73ff7079b4ea7a88cedbcaa452bda7 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Thu, 1 Feb 2024 13:33:20 +0700 Subject: [PATCH 30/31] address comments --- crates/router/src/connector/stancer.rs | 29 +++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/crates/router/src/connector/stancer.rs b/crates/router/src/connector/stancer.rs index c81a19e65dc..cc50ce85660 100644 --- a/crates/router/src/connector/stancer.rs +++ b/crates/router/src/connector/stancer.rs @@ -126,14 +126,19 @@ impl ConnectorCommon for Stancer { message, error_type, } = response; + let payment_id = message["id"].to_string(); Ok(ErrorResponse { status_code: res.status_code, code: error_type, message: message.to_string(), - reason: None, + reason: Some(message.to_string()), attempt_status: None, - connector_transaction_id: None, + connector_transaction_id: if payment_id.starts_with("paym_") { + Some(payment_id) + } else { + None + }, }) } } @@ -198,7 +203,7 @@ impl ConnectorIntegration CustomResult { - Ok(format!("{}{}", self.base_url(connectors), "v1/checkout")) + Ok(format!("{}v1/checkout", self.base_url(connectors))) } async fn execute_pretasks( @@ -316,9 +321,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( - "{}{}/{}", + "{}v1/checkout/{}", self.base_url(_connectors), - "v1/checkout", req.request.get_connector_transaction_id()? )) } @@ -383,9 +387,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( - "{}{}/{}", + "{}v1/checkout/{}", self.base_url(connectors), - "v1/checkout", req.request.connector_transaction_id )) } @@ -472,9 +475,9 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + connectors: &settings::Connectors, ) -> CustomResult { - Ok(format!("{}{}", self.base_url(_connectors), "v1/refunds")) + Ok(format!("{}v1/refunds", self.base_url(connectors))) } fn get_request_body( @@ -554,9 +557,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( - "{}{}/{}", + "{}v1/refunds/{}", self.base_url(connectors), - "v1/refunds", req.request.get_connector_refund_id()? )) } @@ -572,9 +574,6 @@ impl ConnectorIntegration CustomResult { let response: Refund = res .response - .parse_struct("stancer Refund") + .parse_struct("stancer RefundSync") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, From 7de44d0d293ed05067d258845be8cb3c073605e7 Mon Sep 17 00:00:00 2001 From: Romain Boces Date: Thu, 1 Feb 2024 13:34:35 +0700 Subject: [PATCH 31/31] comment connector --- crates/common_enums/src/enums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 1be959f7c31..e24b14d947f 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -151,7 +151,7 @@ pub enum RoutableConnectors { Shift4, Signifyd, Square, - Stancer, + // Stancer, Stax, Stripe, Trustpay,