diff --git a/connector-template/mod.rs b/connector-template/mod.rs index cecf5ef1c6..ce189a33fc 100644 --- a/connector-template/mod.rs +++ b/connector-template/mod.rs @@ -1,9 +1,12 @@ pub mod transformers; -use std::fmt::Debug; use error_stack::{report, ResultExt}; use masking::ExposeInterface; +use common_utils::{ + types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector} +}; +use super::utils::{self as connector_utils}; use crate::{ events::connector_api_logs::ConnectorEvent, configs::settings, @@ -22,8 +25,18 @@ use crate::{ use transformers as {{project-name | downcase}}; -#[derive(Debug, Clone)] -pub struct {{project-name | downcase | pascal_case}}; +#[derive(Clone)] +pub struct {{project-name | downcase | pascal_case}} { + amount_converter: &'static (dyn AmountConvertor + Sync) +} + +impl {{project-name | downcase | pascal_case}} { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMinorUnitForConnector + } + } +} impl api::Payment for {{project-name | downcase | pascal_case}} {} impl api::PaymentSession for {{project-name | downcase | pascal_case}} {} @@ -164,13 +177,17 @@ impl } fn get_request_body(&self, req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors,) -> CustomResult { + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + let connector_router_data = - {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount, + {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::from(( + amount, req, - ))?; + )); let connector_req = {{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -391,13 +408,17 @@ impl } fn get_request_body(&self, req: &types::RefundsRouterData, _connectors: &settings::Connectors,) -> CustomResult { + let refund_amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_router_data = - {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.refund_amount, + {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RouterData::from(( + refund_amount, req, - ))?; + )); let connector_req = {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/connector-template/test.rs b/connector-template/test.rs index f408070fe3..5b5ba6a138 100644 --- a/connector-template/test.rs +++ b/connector-template/test.rs @@ -1,6 +1,5 @@ use masking::Secret; use router::{ - core::utils as core_utils, types::{self, api, storage::enums, }}; @@ -11,10 +10,10 @@ use test_utils::connector_auth; struct {{project-name | downcase | pascal_case}}Test; impl ConnectorActions for {{project-name | downcase | pascal_case}}Test {} impl utils::Connector for {{project-name | downcase | pascal_case}}Test { - fn get_data(&self) -> types::api::ConnectorData { + fn get_data(&self) -> api::ConnectorData { use router::connector::{{project-name | downcase | pascal_case}}; - types::api::ConnectorData { - connector: Box::new(&{{project-name | downcase | pascal_case}}), + api::ConnectorData { + connector: Box::new({{project-name | downcase | pascal_case}}::new()), connector_name: types::Connector::{{project-name | downcase | pascal_case}}, get_token: types::api::GetToken::Connector, merchant_connector_id: None, @@ -94,7 +93,7 @@ async fn should_sync_authorized_payment() { .psync_retry_till_status_matches( enums::AttemptStatus::Authorized, Some(types::PaymentsSyncData { - connector_transaction_id: router::types::ResponseId::ConnectorTransactionId( + connector_transaction_id: types::ResponseId::ConnectorTransactionId( txn_id.unwrap(), ), ..Default::default() @@ -198,7 +197,7 @@ async fn should_sync_auto_captured_payment() { .psync_retry_till_status_matches( enums::AttemptStatus::Charged, Some(types::PaymentsSyncData { - connector_transaction_id: router::types::ResponseId::ConnectorTransactionId( + connector_transaction_id: types::ResponseId::ConnectorTransactionId( txn_id.unwrap(), ), capture_method: Some(enums::CaptureMethod::Automatic), @@ -310,7 +309,7 @@ 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 { + payment_method_data: api::PaymentMethodData::Card(api::Card { card_exp_month: Secret::new("20".to_string()), ..utils::CCardType::default().0 }), @@ -332,7 +331,7 @@ 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 { + payment_method_data: api::PaymentMethodData::Card(api::Card { card_exp_year: Secret::new("2000".to_string()), ..utils::CCardType::default().0 }), diff --git a/connector-template/transformers.rs b/connector-template/transformers.rs index fb08c1026f..9ba5dd7e35 100644 --- a/connector-template/transformers.rs +++ b/connector-template/transformers.rs @@ -1,42 +1,38 @@ use serde::{Deserialize, Serialize}; use masking::Secret; +use common_utils::types::{StringMinorUnit}; use crate::{connector::utils::{PaymentsAuthorizeRequestData},core::errors,types::{self, domain, api, storage::enums}}; //TODO: Fill the struct with respective fields pub struct {{project-name | downcase | pascal_case}}RouterData { - pub amount: MinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub amount: StringMinorUnit, // 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, + From<( + StringMinorUnit, T, )> for {{project-name | downcase | pascal_case}}RouterData { - type Error = error_stack::Report; - fn try_from( - (_currency_unit, _currency, amount, item): ( - &types::api::CurrencyUnit, - types::storage::enums::Currency, - i64, + fn from( + (amount, item): ( + StringMinorUnit, T, ), - ) -> Result { + ) -> Self { //Todo : use utils to convert the amount to the type of amount that a connector accepts - Ok(Self { + Self { amount, router_data: item, - }) + } } } //TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, Eq, PartialEq)] +#[derive(Default, Debug, Serialize, PartialEq)] pub struct {{project-name | downcase | pascal_case}}PaymentsRequest { - amount: i64, + amount: StringMinorUnit, card: {{project-name | downcase | pascal_case}}Card } @@ -62,7 +58,7 @@ impl TryFrom<&{{project-name | downcase | pascal_case}}RouterData<&types::Paymen complete: item.router_data.request.is_auto_capture()?, }; Ok(Self { - amount: item.amount.to_owned(), + amount: item.amount.clone(), card, }) } @@ -141,7 +137,7 @@ impl TryFrom TryFrom<&{{project-name | downcase | pascal_case}}RouterData<&types::RefundsRouterData>> for {{project-name | downcase | pascal_case}}RefundRequest { diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 0d379ff296..9a14475380 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -199,6 +199,7 @@ impl Connector { | Self::DummyConnector6 | Self::DummyConnector7 => false, Self::Aci + // Add Separate authentication support for connectors | Self::Adyen | Self::Adyenplatform | Self::Airwallex diff --git a/crates/router/src/connector/iatapay.rs b/crates/router/src/connector/iatapay.rs index 62c257fa43..c3e8344198 100644 --- a/crates/router/src/connector/iatapay.rs +++ b/crates/router/src/connector/iatapay.rs @@ -1,9 +1,12 @@ pub mod transformers; -use std::fmt::Debug; - use base64::Engine; -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent}; +use common_utils::{ + crypto, + ext_traits::ByteSliceExt, + request::RequestContent, + types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector}, +}; use error_stack::ResultExt; use masking::PeekInterface; use transformers as iatapay; @@ -29,8 +32,18 @@ use crate::{ utils::BytesExt, }; -#[derive(Debug, Clone)] -pub struct Iatapay; +#[derive(Clone)] +pub struct Iatapay { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Iatapay { + pub fn new() -> &'static Self { + &Self { + amount_converter: &FloatMajorUnitForConnector, + } + } +} impl api::Payment for Iatapay {} impl api::PaymentSession for Iatapay {} @@ -316,12 +329,13 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = iatapay::IatapayRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, - req.request.amount, - req, - ))?; + )?; + + let connector_router_data = iatapay::IatapayRouterData::try_from((amount, req))?; let connector_req = iatapay::IatapayPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -506,12 +520,13 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = iatapay::IatapayRouterData::try_from(( - &self.get_currency_unit(), + let refund_amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, req.request.currency, - req.request.refund_amount, - req, - ))?; + )?; + + let connector_router_data = iatapay::IatapayRouterData::try_from((refund_amount, req))?; let connector_req = iatapay::IatapayRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/iatapay/transformers.rs b/crates/router/src/connector/iatapay/transformers.rs index ec1deb34ce..1d597a3dc8 100644 --- a/crates/router/src/connector/iatapay/transformers.rs +++ b/crates/router/src/connector/iatapay/transformers.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use common_utils::{errors::CustomResult, ext_traits::Encode}; +use common_utils::{errors::CustomResult, ext_traits::Encode, types::FloatMajorUnit}; use error_stack::ResultExt; use masking::{Secret, SwitchStrategy}; use serde::{Deserialize, Serialize}; @@ -34,16 +34,14 @@ impl TryFrom<&types::RefreshTokenRouterData> for IatapayAuthUpdateRequest { } #[derive(Debug, Serialize)] pub struct IatapayRouterData { - amount: f64, + amount: FloatMajorUnit, router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for IatapayRouterData { +impl TryFrom<(FloatMajorUnit, T)> for IatapayRouterData { type Error = error_stack::Report; - fn try_from( - (currency_unit, currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), - ) -> Result { + fn try_from((amount, item): (FloatMajorUnit, T)) -> Result { Ok(Self { - amount: connector_util::get_amount_as_f64(currency_unit, amount, currency)?, + amount, router_data: item, }) } @@ -96,7 +94,7 @@ pub enum PreferredCheckoutMethod { pub struct IatapayPaymentsRequest { merchant_id: Secret, merchant_payment_id: Option, - amount: f64, + amount: FloatMajorUnit, currency: common_enums::Currency, country: common_enums::CountryAlpha2, locale: String, @@ -307,7 +305,7 @@ pub struct IatapayPaymentsResponse { pub iata_refund_id: Option, pub merchant_id: Option>, pub merchant_payment_id: Option, - pub amount: f64, + pub amount: FloatMajorUnit, pub currency: String, pub checkout_methods: Option, pub failure_code: Option, @@ -429,7 +427,7 @@ impl pub struct IatapayRefundRequest { pub merchant_id: Secret, pub merchant_refund_id: Option, - pub amount: f64, + pub amount: FloatMajorUnit, pub currency: String, pub bank_transfer_description: Option, pub notification_url: String, @@ -486,7 +484,7 @@ pub struct RefundResponse { iata_refund_id: String, status: RefundStatus, merchant_refund_id: String, - amount: f64, + amount: FloatMajorUnit, currency: String, bank_transfer_description: Option, failure_code: Option, @@ -498,7 +496,7 @@ pub struct RefundResponse { clearance_date_time: Option, iata_payment_id: Option, merchant_payment_id: Option, - payment_amount: Option, + payment_amount: Option, merchant_id: Option>, account_country: Option, } @@ -600,7 +598,7 @@ pub struct IatapayPaymentWebhookBody { pub merchant_payment_id: Option, pub failure_code: Option, pub failure_details: Option, - pub amount: f64, + pub amount: FloatMajorUnit, pub currency: String, pub checkout_methods: Option, } @@ -613,7 +611,7 @@ pub struct IatapayRefundWebhookBody { pub merchant_refund_id: Option, pub failure_code: Option, pub failure_details: Option, - pub amount: f64, + pub amount: FloatMajorUnit, pub currency: String, } diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 97075aff79..d7a05cfa30 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -31,6 +31,7 @@ use crate::{ transformers::ForeignTryFrom, ErrorResponse, Response, }, + // transformers::{ForeignFrom, ForeignTryFrom}, utils::{handle_json_response_deserialization_failure, BytesExt}, }; @@ -864,7 +865,7 @@ impl ConnectorIntegration Ok(ConnectorEnum::Old(Box::new(&connector::Helcim))), - enums::Connector::Iatapay => Ok(ConnectorEnum::Old(Box::new(&connector::Iatapay))), + enums::Connector::Iatapay => { + Ok(ConnectorEnum::Old(Box::new(connector::Iatapay::new()))) + } enums::Connector::Klarna => Ok(ConnectorEnum::Old(Box::new(&connector::Klarna))), enums::Connector::Mollie => Ok(ConnectorEnum::Old(Box::new(&connector::Mollie))), enums::Connector::Nmi => Ok(ConnectorEnum::Old(Box::new(connector::Nmi::new()))), diff --git a/crates/router/tests/connectors/iatapay.rs b/crates/router/tests/connectors/iatapay.rs index 1317ec917e..577da6ce68 100644 --- a/crates/router/tests/connectors/iatapay.rs +++ b/crates/router/tests/connectors/iatapay.rs @@ -15,7 +15,7 @@ impl Connector for IatapayTest { fn get_data(&self) -> api::ConnectorData { use router::connector::Iatapay; utils::construct_connector_data_old( - Box::new(&Iatapay), + Box::new(Iatapay::new()), types::Connector::Iatapay, api::GetToken::Connector, None, diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh index df25077afa..f3e928d0e1 100755 --- a/scripts/add_connector.sh +++ b/scripts/add_connector.sh @@ -53,15 +53,16 @@ find_prev_connector $payment_gateway previous_connector previous_connector_camelcase="$(tr '[:lower:]' '[:upper:]' <<< ${previous_connector:0:1})${previous_connector:1}" sed -i'' -e "s|pub mod $previous_connector;|pub mod $previous_connector;\npub mod ${payment_gateway};|" $conn.rs sed -i'' -e "s/};/${payment_gateway}::${payment_gateway_camelcase},\n};/" $conn.rs -sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tenums::Connector::${payment_gateway_camelcase} => Ok(Box::new(\&connector::${payment_gateway_camelcase})),|" $src/types/api.rs +sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tenums::Connector::${payment_gateway_camelcase} => Ok(Box::new(\connector::${payment_gateway_camelcase}::new())),|" $src/types/api.rs sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tRoutableConnectors::${payment_gateway_camelcase} => euclid_enums::Connector::${payment_gateway_camelcase},|" crates/api_models/src/routing.rs sed -i'' -e "s/pub $previous_connector: \(.*\)/pub $previous_connector: \1\n\tpub ${payment_gateway}: ConnectorParams,/" $src/configs/settings.rs sed -i'' -e "s|$previous_connector.base_url \(.*\)|$previous_connector.base_url \1\n${payment_gateway}.base_url = \"$base_url\"|" config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml sed -r -i'' -e "s/\"$previous_connector\",/\"$previous_connector\",\n \"${payment_gateway}\",/" config/development.toml config/docker_compose.toml config/config.example.toml loadtest/config/development.toml sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/api_models/src/enums.rs -sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/euclid/src/enums.rs +sed -i '' -e "/\/\/ Add Separate authentication support for connectors/{N;s/\(.*\)\n/\1\n\t\t\t| Self::${payment_gateway_camelcase}\n/;}" crates/api_models/src/enums.rs sed -i '' -e "s/\(match connector_name {\)/\1\n\t\tapi_enums::Connector::${payment_gateway_camelcase} => {${payment_gateway}::transformers::${payment_gateway_camelcase}AuthType::try_from(val)?;Ok(())}/" $src/core/admin.rs sed -i'' -e "s/\(pub enum RoutableConnectors {\)/\1\n\t${payment_gateway_camelcase},/" crates/common_enums/src/enums.rs +sed -i '' -e "s/\(pub enum Connector {\)/\1\n\t${payment_gateway_camelcase},/" crates/euclid/src/enums.rs sed -i'' -e "s|$previous_connector_camelcase \(.*\)|$previous_connector_camelcase \1\n\t\t\tapi_enums::Connector::${payment_gateway_camelcase} => Self::${payment_gateway_camelcase},|" $src/types/transformers.rs sed -i'' -e "s/^default_imp_for_\(.*\)/default_imp_for_\1\n\tconnector::${payment_gateway_camelcase},/" $src/core/payments/flows.rs