Skip to content

Commit

Permalink
feat(connector): [noon] add revoke mandate (#3487)
Browse files Browse the repository at this point in the history
  • Loading branch information
SamraatBansal authored Jan 30, 2024
1 parent 431ccb1 commit b5bc8c4
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 5 deletions.
76 changes: 76 additions & 0 deletions crates/router/src/connector/noon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ impl api::Refund for Noon {}
impl api::RefundExecute for Noon {}
impl api::RefundSync for Noon {}
impl api::PaymentToken for Noon {}
impl api::ConnectorMandateRevoke for Noon {}

impl
ConnectorIntegration<
Expand Down Expand Up @@ -492,6 +493,81 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
}
}

impl
ConnectorIntegration<
api::MandateRevoke,
types::MandateRevokeRequestData,
types::MandateRevokeResponseData,
> for Noon
{
fn get_headers(
&self,
req: &types::MandateRevokeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<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::MandateRevokeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
Ok(format!("{}payment/v1/order", self.base_url(connectors)))
}
fn build_request(
&self,
req: &types::MandateRevokeRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::MandateRevokeType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::MandateRevokeType::get_headers(
self, req, connectors,
)?)
.set_body(types::MandateRevokeType::get_request_body(
self, req, connectors,
)?)
.build(),
))
}
fn get_request_body(
&self,
req: &types::MandateRevokeRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let connector_req = noon::NoonRevokeMandateRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}

fn handle_response(
&self,
data: &types::MandateRevokeRouterData,
res: Response,
) -> CustomResult<types::MandateRevokeRouterData, errors::ConnectorError> {
let response: noon::NoonRevokeMandateResponse = res
.response
.parse_struct("Noon NoonRevokeMandateResponse")
.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 {
fn get_headers(
&self,
Expand Down
95 changes: 91 additions & 4 deletions crates/router/src/connector/noon/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};

use crate::{
connector::utils::{
self as conn_utils, CardData, PaymentsAuthorizeRequestData, RouterData, WalletData,
self as conn_utils, CardData, PaymentsAuthorizeRequestData, RevokeMandateRequestData,
RouterData, WalletData,
},
core::errors,
services,
Expand All @@ -30,11 +31,13 @@ pub enum NoonSubscriptionType {
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NoonSubscriptionData {
#[serde(rename = "type")]
subscription_type: NoonSubscriptionType,
//Short description about the subscription.
name: String,
max_amount: Option<String>,
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -168,12 +171,13 @@ pub enum NoonPaymentData {
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "UPPERCASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum NoonApiOperations {
Initiate,
Capture,
Reverse,
Refund,
CancelSubscription,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -335,6 +339,21 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest {
NoonSubscriptionData {
subscription_type: NoonSubscriptionType::Unscheduled,
name: name.clone(),
max_amount: item
.request
.setup_mandate_details
.clone()
.and_then(|mandate_details| match mandate_details.mandate_type {
Some(data_models::mandates::MandateDataType::SingleUse(mandate))
| Some(data_models::mandates::MandateDataType::MultiUse(Some(
mandate,
))) => Some(
conn_utils::to_currency_base_unit(mandate.amount, mandate.currency)
.ok(),
),
_ => None,
})
.flatten(),
},
true,
)) {
Expand Down Expand Up @@ -450,7 +469,7 @@ impl ForeignFrom<(NoonPaymentStatus, Self)> for enums::AttemptStatus {
}

#[derive(Debug, Serialize, Deserialize)]
pub struct NoonSubscriptionResponse {
pub struct NoonSubscriptionObject {
identifier: String,
}

Expand All @@ -475,7 +494,7 @@ pub struct NoonCheckoutData {
pub struct NoonPaymentsResponseResult {
order: NoonPaymentsOrderResponse,
checkout_data: Option<NoonCheckoutData>,
subscription: Option<NoonSubscriptionResponse>,
subscription: Option<NoonSubscriptionObject>,
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -603,6 +622,25 @@ impl TryFrom<&types::PaymentsCancelRouterData> for NoonPaymentsCancelRequest {
}
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NoonRevokeMandateRequest {
api_operation: NoonApiOperations,
subscription: NoonSubscriptionObject,
}

impl TryFrom<&types::MandateRevokeRouterData> for NoonRevokeMandateRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(item: &types::MandateRevokeRouterData) -> Result<Self, Self::Error> {
Ok(Self {
api_operation: NoonApiOperations::CancelSubscription,
subscription: NoonSubscriptionObject {
identifier: item.request.get_connector_mandate_id()?,
},
})
}
}

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> {
Expand All @@ -624,6 +662,55 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for NoonPaymentsActionRequest {
})
}
}
#[derive(Debug, Deserialize)]
pub enum NoonRevokeStatus {
Cancelled,
}

#[derive(Debug, Deserialize)]
pub struct NoonCancelSubscriptionObject {
status: NoonRevokeStatus,
}

#[derive(Debug, Deserialize)]
pub struct NoonRevokeMandateResult {
subscription: NoonCancelSubscriptionObject,
}

#[derive(Debug, Deserialize)]
pub struct NoonRevokeMandateResponse {
result: NoonRevokeMandateResult,
}

impl<F>
TryFrom<
types::ResponseRouterData<
F,
NoonRevokeMandateResponse,
types::MandateRevokeRequestData,
types::MandateRevokeResponseData,
>,
> for types::RouterData<F, types::MandateRevokeRequestData, types::MandateRevokeResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
item: types::ResponseRouterData<
F,
NoonRevokeMandateResponse,
types::MandateRevokeRequestData,
types::MandateRevokeResponseData,
>,
) -> Result<Self, Self::Error> {
match item.response.result.subscription.status {
NoonRevokeStatus::Cancelled => Ok(Self {
response: Ok(types::MandateRevokeResponseData {
mandate_status: common_enums::MandateStatus::Revoked,
}),
..item.data
}),
}
}
}

#[derive(Debug, Default, Deserialize, Clone)]
#[serde(rename_all = "UPPERCASE")]
Expand Down
1 change: 0 additions & 1 deletion crates/router/src/core/payments/flows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2247,7 +2247,6 @@ default_imp_for_revoking_mandates!(
connector::Multisafepay,
connector::Nexinets,
connector::Nmi,
connector::Noon,
connector::Nuvei,
connector::Opayo,
connector::Opennode,
Expand Down

0 comments on commit b5bc8c4

Please sign in to comment.