feat(connector): send metadata in payment authorize request for noon nmi cryptopay (#3325)

This commit is contained in:
Hrithikesh
2024-02-06 19:04:19 +05:30
committed by GitHub
parent 2c52b377e0
commit ebe4ac30a8
6 changed files with 100 additions and 17 deletions

View File

@ -642,7 +642,7 @@ pub struct PaymentMethodListResponse {
pub redirect_url: Option<String>,
/// currency of the Payment to be done
#[schema(example = "USD")]
#[schema(example = "USD", value_type = Currency)]
pub currency: Option<api_enums::Currency>,
/// Information about the payment method

View File

@ -1,3 +1,4 @@
use common_utils::pii;
use masking::Secret;
use reqwest::Url;
use serde::{Deserialize, Serialize};
@ -47,6 +48,7 @@ pub struct CryptopayPaymentsRequest {
pay_currency: String,
success_redirect_url: Option<String>,
unsuccess_redirect_url: Option<String>,
metadata: Option<pii::SecretSerdeValue>,
custom_id: String,
}
@ -66,6 +68,7 @@ impl TryFrom<&CryptopayRouterData<&types::PaymentsAuthorizeRouterData>>
pay_currency,
success_redirect_url: item.router_data.request.router_return_url.clone(),
unsuccess_redirect_url: item.router_data.request.router_return_url.clone(),
metadata: item.router_data.request.metadata.clone(),
custom_id: item.router_data.connector_request_reference_id.clone(),
})
}

View File

@ -1,6 +1,6 @@
use api_models::webhooks;
use cards::CardNumber;
use common_utils::{errors::CustomResult, ext_traits::XmlExt};
use common_utils::{errors::CustomResult, ext_traits::XmlExt, pii};
use error_stack::{IntoReport, Report, ResultExt};
use masking::{ExposeInterface, PeekInterface, Secret};
use serde::{Deserialize, Serialize};
@ -395,9 +395,35 @@ pub struct NmiPaymentsRequest {
currency: enums::Currency,
#[serde(flatten)]
payment_method: PaymentMethod,
#[serde(flatten)]
merchant_defined_field: Option<NmiMerchantDefinedField>,
orderid: String,
}
#[derive(Debug, Serialize)]
pub struct NmiMerchantDefinedField {
#[serde(flatten)]
inner: std::collections::BTreeMap<String, Secret<String>>,
}
impl NmiMerchantDefinedField {
pub fn new(metadata: &pii::SecretSerdeValue) -> Self {
let metadata_as_string = metadata.peek().to_string();
let hash_map: std::collections::BTreeMap<String, serde_json::Value> =
serde_json::from_str(&metadata_as_string).unwrap_or(std::collections::BTreeMap::new());
let inner = hash_map
.into_iter()
.enumerate()
.map(|(index, (hs_key, hs_value))| {
let nmi_key = format!("merchant_defined_field_{}", index + 1);
let nmi_value = format!("{hs_key}={hs_value}");
(nmi_key, Secret::new(nmi_value))
})
.collect();
Self { inner }
}
}
#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum PaymentMethod {
@ -443,6 +469,12 @@ impl TryFrom<&NmiRouterData<&types::PaymentsAuthorizeRouterData>> for NmiPayment
amount,
currency: item.router_data.request.currency,
payment_method,
merchant_defined_field: item
.router_data
.request
.metadata
.as_ref()
.map(NmiMerchantDefinedField::new),
orderid: item.router_data.connector_request_reference_id.clone(),
})
}
@ -556,6 +588,7 @@ impl TryFrom<&types::SetupMandateRouterData> for NmiPaymentsRequest {
amount: 0.0,
currency: item.request.currency,
payment_method,
merchant_defined_field: None,
orderid: item.connector_request_reference_id.clone(),
})
}

View File

@ -5,8 +5,9 @@ use std::fmt::Debug;
use base64::Engine;
use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent};
use diesel_models::enums;
use error_stack::{IntoReport, ResultExt};
use error_stack::{IntoReport, Report, ResultExt};
use masking::PeekInterface;
use router_env::logger;
use transformers as noon;
use crate::{
@ -28,7 +29,7 @@ use crate::{
api::{self, ConnectorCommon, ConnectorCommonExt},
ErrorResponse, Response,
},
utils::BytesExt,
utils::{self, BytesExt},
};
#[derive(Debug, Clone)]
@ -127,19 +128,23 @@ impl ConnectorCommon for Noon {
&self,
res: Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
let response: noon::NoonErrorResponse = res
.response
.parse_struct("NoonErrorResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
let response: Result<noon::NoonErrorResponse, Report<common_utils::errors::ParsingError>> =
res.response.parse_struct("NoonErrorResponse");
Ok(ErrorResponse {
match response {
Ok(noon_error_response) => Ok(ErrorResponse {
status_code: res.status_code,
code: response.result_code.to_string(),
message: response.class_description,
reason: Some(response.message),
code: consts::NO_ERROR_CODE.to_string(),
message: noon_error_response.class_description,
reason: Some(noon_error_response.message),
attempt_status: None,
connector_transaction_id: None,
})
}),
Err(error_message) => {
logger::error!(deserialization_error =? error_message);
utils::handle_json_response_deserialization_failure(res, "noon".to_owned())
}
}
}
}

View File

@ -1,6 +1,6 @@
use common_utils::pii;
use error_stack::ResultExt;
use masking::Secret;
use masking::{PeekInterface, Secret};
use serde::{Deserialize, Serialize};
use crate::{
@ -67,9 +67,46 @@ pub struct NoonOrder {
reference: String,
//Short description of the order.
name: String,
nvp: Option<NoonOrderNvp>,
ip_address: Option<Secret<String, pii::IpAddress>>,
}
#[derive(Debug, Serialize)]
pub struct NoonOrderNvp {
#[serde(flatten)]
inner: std::collections::BTreeMap<String, Secret<String>>,
}
fn get_value_as_string(value: &serde_json::Value) -> String {
match value {
serde_json::Value::String(string) => string.to_owned(),
serde_json::Value::Null
| serde_json::Value::Bool(_)
| serde_json::Value::Number(_)
| serde_json::Value::Array(_)
| serde_json::Value::Object(_) => value.to_string(),
}
}
impl NoonOrderNvp {
pub fn new(metadata: &pii::SecretSerdeValue) -> Self {
let metadata_as_string = metadata.peek().to_string();
let hash_map: std::collections::BTreeMap<String, serde_json::Value> =
serde_json::from_str(&metadata_as_string).unwrap_or(std::collections::BTreeMap::new());
let inner = hash_map
.into_iter()
.enumerate()
.map(|(index, (hs_key, hs_value))| {
let noon_key = format!("{}", index + 1);
// to_string() function on serde_json::Value returns a string with "" quotes. Noon doesn't allow this. Hence get_value_as_string function
let noon_value = format!("{hs_key}={}", get_value_as_string(&hs_value));
(noon_key, Secret::new(noon_value))
})
.collect();
Self { inner }
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum NoonPaymentActions {
@ -365,6 +402,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest {
category,
reference: item.connector_request_reference_id.clone(),
name,
nvp: item.request.metadata.as_ref().map(NoonOrderNvp::new),
ip_address,
};
let payment_action = if item.request.is_auto_capture()? {

View File

@ -11637,6 +11637,7 @@
"PaymentMethodListResponse": {
"type": "object",
"required": [
"currency",
"payment_methods",
"mandate_payment",
"show_surcharge_breakup_screen"
@ -11648,6 +11649,9 @@
"example": "https://www.google.com",
"nullable": true
},
"currency": {
"$ref": "#/components/schemas/Currency"
},
"payment_methods": {
"type": "array",
"items": {