From 27610361b948c56f3422caa7c70beeb9e87bb69c Mon Sep 17 00:00:00 2001 From: SamraatBansal <55536657+SamraatBansal@users.noreply.github.com> Date: Tue, 23 May 2023 16:35:39 +0530 Subject: [PATCH] feat(connector): [Noon] Add Card Payments, Capture, Void and Refund (#1207) --- crates/api_models/src/enums.rs | 4 +- crates/router/src/connector/noon.rs | 165 ++++++-- .../router/src/connector/noon/transformers.rs | 356 ++++++++++++++---- crates/router/src/core/payments/flows.rs | 1 - crates/router/src/types/api.rs | 2 +- .../router/tests/connectors/connector_auth.rs | 2 +- crates/router/tests/connectors/noon.rs | 12 +- .../router/tests/connectors/sample_auth.toml | 4 +- 8 files changed, 430 insertions(+), 116 deletions(-) diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 0b1726daaa..f91732cfa7 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -616,7 +616,7 @@ pub enum Connector { Multisafepay, Nexinets, Nmi, - // Noon, added as template code for future usage + Noon, Nuvei, // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage Paypal, @@ -698,7 +698,7 @@ pub enum RoutableConnectors { Multisafepay, Nexinets, Nmi, - // Noon, added as template code for future usage + Noon, Nuvei, Opennode, // Payeezy, As psync and rsync are not supported by this connector, it is added as template code for future usage diff --git a/crates/router/src/connector/noon.rs b/crates/router/src/connector/noon.rs index 2be0faddbc..06dde9243b 100644 --- a/crates/router/src/connector/noon.rs +++ b/crates/router/src/connector/noon.rs @@ -2,12 +2,18 @@ mod transformers; use std::fmt::Debug; +use base64::Engine; use error_stack::{IntoReport, ResultExt}; use transformers as noon; +use super::utils::PaymentsSyncRequestData; use crate::{ configs::settings, - core::errors::{self, CustomResult}, + consts, + core::{ + errors::{self, CustomResult}, + payments, + }, headers, services::{self, ConnectorIntegration}, types::{ @@ -80,9 +86,16 @@ impl ConnectorCommon for Noon { &self, auth_type: &types::ConnectorAuthType, ) -> CustomResult, errors::ConnectorError> { - let auth = noon::NoonAuthType::try_from(auth_type) - .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - Ok(vec![(headers::AUTHORIZATION.to_string(), auth.api_key)]) + let auth = noon::NoonAuthType::try_from(auth_type)?; + + let encoded_api_key = consts::BASE64_ENGINE.encode(format!( + "{}.{}:{}", + auth.business_identifier, auth.application_identifier, auth.api_key + )); + Ok(vec![( + headers::AUTHORIZATION.to_string(), + format!("Key_Test {encoded_api_key}"), + )]) } fn build_error_response( @@ -96,9 +109,9 @@ impl ConnectorCommon for Noon { Ok(ErrorResponse { status_code: res.status_code, - code: response.code, + code: response.result_code.to_string(), message: response.message, - reason: response.reason, + reason: Some(response.class_description), }) } } @@ -137,9 +150,9 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!("{}payment/v1/order", self.base_url(connectors))) } fn get_request_body( @@ -187,7 +200,6 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + let connector_transaction_id = req.request.get_connector_transaction_id()?; + Ok(format!( + "{}payment/v1/order/{connector_transaction_id}", + self.base_url(connectors) + )) } fn build_request( @@ -250,7 +266,6 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!("{}payment/v1/order", self.base_url(connectors))) } fn get_request_body( &self, - _req: &types::PaymentsCaptureRouterData, + req: &types::PaymentsCaptureRouterData, ) -> CustomResult, errors::ConnectorError> { - Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + let req_obj = noon::NoonPaymentsActionRequest::try_from(req)?; + let noon_req = + utils::Encode::::encode_to_string_of_json(&req_obj) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(noon_req)) } fn build_request( @@ -323,7 +342,6 @@ impl ConnectorIntegration for Noon { + fn get_headers( + &self, + req: &types::PaymentsCancelRouterData, + 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::PaymentsCancelRouterData, + connectors: &settings::Connectors, + ) -> CustomResult { + Ok(format!("{}payment/v1/order", self.base_url(connectors))) + } + fn get_request_body( + &self, + req: &types::PaymentsCancelRouterData, + ) -> CustomResult, errors::ConnectorError> { + let connector_req = noon::NoonPaymentsCancelRequest::try_from(req)?; + let noon_req = utils::Encode::::encode_to_string_of_json( + &connector_req, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + Ok(Some(noon_req)) + } + + fn build_request( + &self, + req: &types::PaymentsCancelRouterData, + connectors: &settings::Connectors, + ) -> CustomResult, errors::ConnectorError> { + Ok(Some( + services::RequestBuilder::new() + .method(services::Method::Post) + .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) + .attach_default_headers() + .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) + .body(types::PaymentsVoidType::get_request_body(self, req)?) + .build(), + )) + } + + fn handle_response( + &self, + data: &types::PaymentsCancelRouterData, + res: Response, + ) -> CustomResult { + let response: noon::NoonPaymentsResponse = res + .response + .parse_struct("Noon PaymentsCancelResponse") + .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 Noon { @@ -355,18 +442,19 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + connectors: &settings::Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!("{}payment/v1/order", self.base_url(connectors))) } fn get_request_body( &self, req: &types::RefundsRouterData, ) -> CustomResult, errors::ConnectorError> { - let req_obj = noon::NoonRefundRequest::try_from(req)?; - let noon_req = utils::Encode::::encode_to_string_of_json(&req_obj) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + let req_obj = noon::NoonPaymentsActionRequest::try_from(req)?; + let noon_req = + utils::Encode::::encode_to_string_of_json(&req_obj) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(noon_req)) } @@ -401,7 +489,6 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!( + "{}payment/v1/order/{}", + self.base_url(connectors), + req.request.connector_transaction_id + )) } fn build_request( @@ -454,10 +545,11 @@ impl ConnectorIntegration CustomResult { - let response: noon::RefundResponse = - res.response - .parse_struct("noon RefundSyncResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let response: noon::RefundSyncResponse = res + .response + .parse_struct("noon RefundSyncResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + types::RouterData::try_from(types::ResponseRouterData { response, data: data.clone(), @@ -474,6 +566,17 @@ impl ConnectorIntegration, + _action: services::PaymentAction, + ) -> CustomResult { + Ok(payments::CallConnectorAction::Trigger) + } +} + #[async_trait::async_trait] impl api::IncomingWebhook for Noon { fn get_webhook_object_reference_id( diff --git a/crates/router/src/connector/noon/transformers.rs b/crates/router/src/connector/noon/transformers.rs index da00cfeee5..71a5ce81f2 100644 --- a/crates/router/src/connector/noon/transformers.rs +++ b/crates/router/src/connector/noon/transformers.rs @@ -2,94 +2,192 @@ use masking::Secret; use serde::{Deserialize, Serialize}; use crate::{ - connector::utils::PaymentsAuthorizeRequestData, + connector::utils::{ + self as conn_utils, PaymentsAuthorizeRequestData, RefundsRequestData, RouterData, + }, core::errors, + services, types::{self, api, storage::enums}, }; -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, Eq, PartialEq)] -pub struct NoonPaymentsRequest { - amount: i64, - card: NoonCard, +#[derive(Debug, Serialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum NoonChannels { + Web, } -#[derive(Default, Debug, Serialize, Eq, PartialEq)] +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonOrder { + amount: String, + currency: storage_models::enums::Currency, + channel: NoonChannels, + category: String, + //Short description of the order. + name: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum NoonPaymentActions { + Authorize, + Sale, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonConfiguration { + payment_action: NoonPaymentActions, + return_url: Option, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] pub struct NoonCard { - name: Secret, - number: cards::CardNumber, + name_on_card: Secret, + number_plain: cards::CardNumber, expiry_month: Secret, expiry_year: Secret, - cvc: Secret, - complete: bool, + cvv: Secret, +} + +#[derive(Debug, Serialize)] +#[serde(tag = "type", content = "data")] +pub enum NoonPaymentData { + Card(NoonCard), +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum NoonApiOperations { + Initiate, + Capture, + Reverse, + Refund, +} +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonPaymentsRequest { + api_operation: NoonApiOperations, + order: NoonOrder, + configuration: NoonConfiguration, + payment_data: NoonPaymentData, } impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest { type Error = error_stack::Report; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { - match item.request.payment_method_data.clone() { - api::PaymentMethodData::Card(req_card) => { - let card = NoonCard { - 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.request.is_auto_capture()?, - }; - Ok(Self { - amount: item.request.amount, - card, - }) - } - _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), - } + let payment_data = match item.request.payment_method_data.clone() { + api::PaymentMethodData::Card(req_card) => Ok(NoonPaymentData::Card(NoonCard { + name_on_card: req_card.card_holder_name, + number_plain: req_card.card_number, + expiry_month: req_card.card_exp_month, + expiry_year: req_card.card_exp_year, + cvv: req_card.card_cvc, + })), + _ => Err(errors::ConnectorError::NotImplemented( + "Payment methods".to_string(), + )), + }?; + + let order = NoonOrder { + amount: conn_utils::to_currency_base_unit(item.request.amount, item.request.currency)?, + currency: item.request.currency, + channel: NoonChannels::Web, + category: "pay".to_string(), + name: item.get_description()?, + }; + let payment_action = if item.request.is_auto_capture()? { + NoonPaymentActions::Sale + } else { + NoonPaymentActions::Authorize + }; + Ok(Self { + api_operation: NoonApiOperations::Initiate, + order, + configuration: NoonConfiguration { + payment_action, + return_url: item.request.router_return_url.clone(), + }, + payment_data, + }) } } -//TODO: Fill the struct with respective fields // Auth Struct pub struct NoonAuthType { pub(super) api_key: String, + pub(super) application_identifier: String, + pub(super) business_identifier: String, } impl TryFrom<&types::ConnectorAuthType> for NoonAuthType { type Error = error_stack::Report; fn try_from(auth_type: &types::ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::HeaderKey { api_key } => Ok(Self { + types::ConnectorAuthType::SignatureKey { + api_key, + key1, + api_secret, + } => Ok(Self { api_key: api_key.to_string(), + application_identifier: api_secret.to_string(), + business_identifier: key1.to_string(), }), _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), } } } -// PaymentsResponse -//TODO: Append the remaining status flags -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] +#[derive(Default, Debug, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum NoonPaymentStatus { - Succeeded, + Authorized, + Captured, + PartiallyCaptured, + Reversed, + #[serde(rename = "3DS_ENROLL_INITIATED")] + ThreeDsEnrollInitiated, Failed, #[default] - Processing, + Pending, } impl From for enums::AttemptStatus { fn from(item: NoonPaymentStatus) -> Self { match item { - NoonPaymentStatus::Succeeded => Self::Charged, + NoonPaymentStatus::Authorized => Self::Authorized, + NoonPaymentStatus::Captured | NoonPaymentStatus::PartiallyCaptured => Self::Charged, + NoonPaymentStatus::Reversed => Self::Voided, + NoonPaymentStatus::ThreeDsEnrollInitiated => Self::AuthenticationPending, NoonPaymentStatus::Failed => Self::Failure, - NoonPaymentStatus::Processing => Self::Authorizing, + NoonPaymentStatus::Pending => Self::Pending, } } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct NoonPaymentsResponse { +#[derive(Default, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonPaymentsOrderResponse { status: NoonPaymentStatus, - id: String, + id: u64, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonCheckoutData { + post_url: url::Url, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonPaymentsResponseResult { + order: NoonPaymentsOrderResponse, + checkout_data: Option, +} + +#[derive(Debug, Deserialize)] +pub struct NoonPaymentsResponse { + result: NoonPaymentsResponseResult, } impl @@ -100,11 +198,20 @@ impl fn try_from( item: types::ResponseRouterData, ) -> Result { + let redirection_data = item.response.result.checkout_data.map(|redirection_data| { + services::RedirectForm::Form { + endpoint: redirection_data.post_url.to_string(), + method: services::Method::Post, + form_fields: std::collections::HashMap::new(), + } + }); Ok(Self { - status: enums::AttemptStatus::from(item.response.status), + status: enums::AttemptStatus::from(item.response.result.order.status), response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - redirection_data: None, + resource_id: types::ResponseId::ConnectorTransactionId( + item.response.result.order.id.to_string(), + ), + redirection_data, mandate_reference: None, connector_metadata: None, network_txn_id: None, @@ -114,52 +221,125 @@ impl } } -//TODO: Fill the struct with respective fields -// REFUND : -// Type definition for RefundRequest -#[derive(Default, Debug, Serialize)] -pub struct NoonRefundRequest { - pub amount: i64, +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonActionTransaction { + amount: String, + currency: storage_models::enums::Currency, } -impl TryFrom<&types::RefundsRouterData> for NoonRefundRequest { +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonActionOrder { + id: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonPaymentsActionRequest { + api_operation: NoonApiOperations, + order: NoonActionOrder, + transaction: NoonActionTransaction, +} + +impl TryFrom<&types::PaymentsCaptureRouterData> for NoonPaymentsActionRequest { type Error = error_stack::Report; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { + let order = NoonActionOrder { + id: item.request.connector_transaction_id.clone(), + }; + let transaction = NoonActionTransaction { + amount: conn_utils::to_currency_base_unit( + item.request.amount_to_capture, + item.request.currency, + )?, + currency: item.request.currency, + }; Ok(Self { - amount: item.request.amount, + api_operation: NoonApiOperations::Capture, + order, + transaction, }) } } -// Type definition for Refund Response +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonPaymentsCancelRequest { + api_operation: NoonApiOperations, + order: NoonActionOrder, +} -#[allow(dead_code)] -#[derive(Debug, Serialize, Default, Deserialize, Clone)] +impl TryFrom<&types::PaymentsCancelRouterData> for NoonPaymentsCancelRequest { + type Error = error_stack::Report; + fn try_from(item: &types::PaymentsCancelRouterData) -> Result { + let order = NoonActionOrder { + id: item.request.connector_transaction_id.clone(), + }; + Ok(Self { + api_operation: NoonApiOperations::Reverse, + order, + }) + } +} + +impl TryFrom<&types::RefundsRouterData> for NoonPaymentsActionRequest { + type Error = error_stack::Report; + fn try_from(item: &types::RefundsRouterData) -> Result { + let order = NoonActionOrder { + id: item.request.connector_transaction_id.clone(), + }; + let transaction = NoonActionTransaction { + amount: conn_utils::to_currency_base_unit( + item.request.refund_amount, + item.request.currency, + )?, + currency: item.request.currency, + }; + Ok(Self { + api_operation: NoonApiOperations::Refund, + order, + transaction, + }) + } +} + +#[derive(Debug, Default, Deserialize, Clone)] +#[serde(rename_all = "UPPERCASE")] pub enum RefundStatus { - Succeeded, + Success, Failed, #[default] - Processing, + Pending, } impl From for enums::RefundStatus { fn from(item: RefundStatus) -> Self { match item { - RefundStatus::Succeeded => Self::Success, + RefundStatus::Success => Self::Success, RefundStatus::Failed => Self::Failure, - RefundStatus::Processing => Self::Pending, - //TODO: Review mapping + RefundStatus::Pending => Self::Pending, } } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct RefundResponse { +#[derive(Default, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct NoonPaymentsTransactionResponse { id: String, status: RefundStatus, } +#[derive(Default, Debug, Deserialize)] +pub struct NoonRefundResponseResult { + transaction: NoonPaymentsTransactionResponse, +} + +#[derive(Default, Debug, Deserialize)] +pub struct RefundResponse { + result: NoonRefundResponseResult, +} + impl TryFrom> for types::RefundsRouterData { @@ -169,36 +349,60 @@ impl TryFrom> ) -> Result { Ok(Self { response: Ok(types::RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), + connector_refund_id: item.response.result.transaction.id, + refund_status: enums::RefundStatus::from(item.response.result.transaction.status), }), ..item.data }) } } -impl TryFrom> +#[derive(Default, Debug, Deserialize)] +pub struct NoonRefundResponseTransactions { + id: String, + status: RefundStatus, +} + +#[derive(Default, Debug, Deserialize)] +pub struct NoonRefundSyncResponseResult { + transactions: Vec, +} + +#[derive(Default, Debug, Deserialize)] +pub struct RefundSyncResponse { + result: NoonRefundSyncResponseResult, +} + +impl TryFrom> for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: types::RefundsResponseRouterData, ) -> Result { + let connector_refund_id = item.data.request.get_connector_refund_id()?; + let noon_transaction: &NoonRefundResponseTransactions = item + .response + .result + .transactions + .iter() + .find(|transaction| transaction.id == connector_refund_id) + .ok_or(errors::ConnectorError::ResponseHandlingFailed)?; + Ok(Self { response: Ok(types::RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), + connector_refund_id: noon_transaction.id.to_owned(), + refund_status: enums::RefundStatus::from(noon_transaction.status.to_owned()), }), ..item.data }) } } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct NoonErrorResponse { - pub status_code: u16, - pub code: String, + pub result_code: u32, pub message: String, - pub reason: Option, + pub class_description: String, } diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index d619e72275..9ac6e9cd3b 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -261,7 +261,6 @@ default_imp_for_connector_redirect_response!( connector::Multisafepay, connector::Nexinets, connector::Nmi, - connector::Noon, connector::Opennode, connector::Payeezy, connector::Payu, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index ce87e7d2ce..0b14654743 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -226,7 +226,7 @@ impl ConnectorData { enums::Connector::Klarna => Ok(Box::new(&connector::Klarna)), enums::Connector::Mollie => Ok(Box::new(&connector::Mollie)), enums::Connector::Nmi => Ok(Box::new(&connector::Nmi)), - // "noon" => Ok(Box::new(&connector::Noon)), added as template code for future usage + enums::Connector::Noon => Ok(Box::new(&connector::Noon)), enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), // "payeezy" => Ok(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage diff --git a/crates/router/tests/connectors/connector_auth.rs b/crates/router/tests/connectors/connector_auth.rs index 6c2b1a1b96..7970b8dbd7 100644 --- a/crates/router/tests/connectors/connector_auth.rs +++ b/crates/router/tests/connectors/connector_auth.rs @@ -25,7 +25,7 @@ pub(crate) struct ConnectorAuthentication { pub mollie: Option, pub multisafepay: Option, pub nexinets: Option, - pub noon: Option, + pub noon: Option, pub nmi: Option, pub nuvei: Option, pub opennode: Option, diff --git a/crates/router/tests/connectors/noon.rs b/crates/router/tests/connectors/noon.rs index 7df526be2f..c426d977c3 100644 --- a/crates/router/tests/connectors/noon.rs +++ b/crates/router/tests/connectors/noon.rs @@ -1,7 +1,10 @@ use std::str::FromStr; use masking::Secret; -use router::types::{self, api, storage::enums}; +use router::types::{ + self, api, + storage::{self, enums}, +}; use crate::{ connector_auth, @@ -16,7 +19,7 @@ impl utils::Connector for NoonTest { use router::connector::Noon; types::api::ConnectorData { connector: Box::new(&Noon), - connector_name: types::Connector::DummyConnector1, + connector_name: types::Connector::Noon, get_token: types::api::GetToken::Connector, } } @@ -41,7 +44,10 @@ fn get_default_payment_info() -> Option { } fn payment_method_details() -> Option { - None + Some(types::PaymentsAuthorizeData { + currency: storage::enums::Currency::AED, + ..utils::PaymentAuthorizeType::default().0 + }) } // Cards Positive Tests diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml index a1d441d88c..77c5aefc77 100644 --- a/crates/router/tests/connectors/sample_auth.toml +++ b/crates/router/tests/connectors/sample_auth.toml @@ -112,4 +112,6 @@ api_secret = "secrect" api_key = "API Key" [noon] -api_key = "API Key" +api_key = "Application API KEY" +api_secret = "Application Identifier" +key1 = "Business Identifier"