feat(connector): [Noon] Add Card Payments, Capture, Void and Refund (#1207)

This commit is contained in:
SamraatBansal
2023-05-23 16:35:39 +05:30
committed by GitHub
parent 9341191e39
commit 27610361b9
8 changed files with 430 additions and 116 deletions

View File

@ -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

View File

@ -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<Vec<(String, String)>, 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<api::Authorize, types::PaymentsAuthorizeData, types::P
fn get_url(
&self,
_req: &types::PaymentsAuthorizeRouterData,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
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<api::Authorize, types::PaymentsAuthorizeData, types::P
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}
fn get_error_response(
@ -215,10 +227,14 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
fn get_url(
&self,
_req: &types::PaymentsSyncRouterData,
_connectors: &settings::Connectors,
req: &types::PaymentsSyncRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
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<api::PSync, types::PaymentsSyncData, types::PaymentsRe
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}
fn get_error_response(
@ -279,16 +294,20 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
fn get_url(
&self,
_req: &types::PaymentsCaptureRouterData,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
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<Option<String>, 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::<noon::NoonPaymentsRequest>::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<api::Capture, types::PaymentsCaptureData, types::Payme
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}
fn get_error_response(
@ -337,6 +355,75 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
for Noon
{
fn get_headers(
&self,
req: &types::PaymentsCancelRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, String)>, 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<String, errors::ConnectorError> {
Ok(format!("{}payment/v1/order", self.base_url(connectors)))
}
fn get_request_body(
&self,
req: &types::PaymentsCancelRouterData,
) -> CustomResult<Option<String>, errors::ConnectorError> {
let connector_req = noon::NoonPaymentsCancelRequest::try_from(req)?;
let noon_req = utils::Encode::<noon::NoonPaymentsCancelRequest>::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<Option<services::Request>, 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<types::PaymentsCancelRouterData, errors::ConnectorError> {
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<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res)
}
}
impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData> for Noon {
@ -355,18 +442,19 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
fn get_url(
&self,
_req: &types::RefundsRouterData<api::Execute>,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
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<api::Execute>,
) -> CustomResult<Option<String>, errors::ConnectorError> {
let req_obj = noon::NoonRefundRequest::try_from(req)?;
let noon_req = utils::Encode::<noon::NoonRefundRequest>::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::<noon::NoonPaymentsActionRequest>::encode_to_string_of_json(&req_obj)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
Ok(Some(noon_req))
}
@ -401,7 +489,6 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
data: data.clone(),
http_code: res.status_code,
})
.change_context(errors::ConnectorError::ResponseHandlingFailed)
}
fn get_error_response(
@ -427,10 +514,14 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
fn get_url(
&self,
_req: &types::RefundSyncRouterData,
_connectors: &settings::Connectors,
req: &types::RefundSyncRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
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<api::RSync, types::RefundsData, types::RefundsResponse
data: &types::RefundSyncRouterData,
res: Response,
) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
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<api::RSync, types::RefundsData, types::RefundsResponse
}
}
impl services::ConnectorRedirectResponse for Noon {
fn get_flow_type(
&self,
_query_params: &str,
_json_payload: Option<serde_json::Value>,
_action: services::PaymentAction,
) -> CustomResult<payments::CallConnectorAction, errors::ConnectorError> {
Ok(payments::CallConnectorAction::Trigger)
}
}
#[async_trait::async_trait]
impl api::IncomingWebhook for Noon {
fn get_webhook_object_reference_id(

View File

@ -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<String>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NoonCard {
name: Secret<String>,
number: cards::CardNumber,
name_on_card: Secret<String>,
number_plain: cards::CardNumber,
expiry_month: Secret<String>,
expiry_year: Secret<String>,
cvc: Secret<String>,
complete: bool,
cvv: Secret<String>,
}
#[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<errors::ConnectorError>;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
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<errors::ConnectorError>;
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
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<NoonPaymentStatus> 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<NoonCheckoutData>,
}
#[derive(Debug, Deserialize)]
pub struct NoonPaymentsResponse {
result: NoonPaymentsResponseResult,
}
impl<F, T>
@ -100,11 +198,20 @@ impl<F, T>
fn try_from(
item: types::ResponseRouterData<F, NoonPaymentsResponse, T, types::PaymentsResponseData>,
) -> Result<Self, Self::Error> {
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<F, T>
}
}
//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<F> TryFrom<&types::RefundsRouterData<F>> 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<errors::ConnectorError>;
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
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<errors::ConnectorError>;
fn try_from(item: &types::PaymentsCancelRouterData) -> Result<Self, Self::Error> {
let order = NoonActionOrder {
id: item.request.connector_transaction_id.clone(),
};
Ok(Self {
api_operation: NoonApiOperations::Reverse,
order,
})
}
}
impl<F> TryFrom<&types::RefundsRouterData<F>> for NoonPaymentsActionRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
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<RefundStatus> 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<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
for types::RefundsRouterData<api::Execute>
{
@ -169,36 +349,60 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
) -> Result<Self, Self::Error> {
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<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
#[derive(Default, Debug, Deserialize)]
pub struct NoonRefundResponseTransactions {
id: String,
status: RefundStatus,
}
#[derive(Default, Debug, Deserialize)]
pub struct NoonRefundSyncResponseResult {
transactions: Vec<NoonRefundResponseTransactions>,
}
#[derive(Default, Debug, Deserialize)]
pub struct RefundSyncResponse {
result: NoonRefundSyncResponseResult,
}
impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundSyncResponse>>
for types::RefundsRouterData<api::RSync>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::RefundsResponseRouterData<api::RSync, RefundResponse>,
item: types::RefundsResponseRouterData<api::RSync, RefundSyncResponse>,
) -> Result<Self, Self::Error> {
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<String>,
pub class_description: String,
}

View File

@ -261,7 +261,6 @@ default_imp_for_connector_redirect_response!(
connector::Multisafepay,
connector::Nexinets,
connector::Nmi,
connector::Noon,
connector::Opennode,
connector::Payeezy,
connector::Payu,

View File

@ -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

View File

@ -25,7 +25,7 @@ pub(crate) struct ConnectorAuthentication {
pub mollie: Option<HeaderKey>,
pub multisafepay: Option<HeaderKey>,
pub nexinets: Option<HeaderKey>,
pub noon: Option<HeaderKey>,
pub noon: Option<SignatureKey>,
pub nmi: Option<HeaderKey>,
pub nuvei: Option<SignatureKey>,
pub opennode: Option<HeaderKey>,

View File

@ -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<utils::PaymentInfo> {
}
fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
None
Some(types::PaymentsAuthorizeData {
currency: storage::enums::Currency::AED,
..utils::PaymentAuthorizeType::default().0
})
}
// Cards Positive Tests

View File

@ -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"