diff --git a/Cargo.lock b/Cargo.lock
index 3b6ae6de28..12f7891cab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -321,6 +321,7 @@ name = "api_models"
version = "0.1.0"
dependencies = [
"common_utils",
+ "error-stack",
"frunk",
"frunk_core",
"masking",
diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml
index f6932a980b..34676b6ab6 100644
--- a/crates/api_models/Cargo.toml
+++ b/crates/api_models/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+error-stack = "0.2.4"
frunk = "0.4.1"
frunk_core = "0.4.1"
serde = { version = "1.0.145", features = ["derive"] }
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 7df79f939e..7c7e681238 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -1,6 +1,6 @@
use std::num::NonZeroI64;
-use common_utils::pii;
+use common_utils::{errors, ext_traits::Encode, pii};
use masking::{PeekInterface, Secret};
use router_derive::Setter;
use time::PrimitiveDateTime;
@@ -15,11 +15,6 @@ pub enum PaymentOp {
Confirm,
}
-#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)]
-pub struct Metadata {
- pub order_details: OrderDetails,
-}
-
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct PaymentsRequest {
@@ -53,7 +48,7 @@ pub struct PaymentsRequest {
pub billing: Option
,
pub statement_descriptor_name: Option,
pub statement_descriptor_suffix: Option,
- pub metadata: Option,
+ pub metadata: Option,
pub client_secret: Option,
pub mandate_data: Option,
pub mandate_id: Option,
@@ -561,21 +556,25 @@ impl From<&VerifyRequest> for MandateValidationFields {
}
}
-impl From for PaymentsResponse {
- fn from(item: PaymentsRequest) -> Self {
+impl TryFrom for PaymentsResponse {
+ type Error = error_stack::Report;
+ fn try_from(item: PaymentsRequest) -> Result {
let payment_id = match item.payment_id {
Some(PaymentIdType::PaymentIntentId(id)) => Some(id),
_ => None,
};
-
- Self {
+ let metadata = item
+ .metadata
+ .map(|a| Encode::::encode_to_value(&a))
+ .transpose()?;
+ Ok(Self {
payment_id,
merchant_id: item.merchant_id,
setup_future_usage: item.setup_future_usage,
off_session: item.off_session,
shipping: item.shipping,
billing: item.billing,
- metadata: item.metadata,
+ metadata,
capture_method: item.capture_method,
payment_method: item.payment_method,
capture_on: item.capture_on,
@@ -592,7 +591,7 @@ impl From for PaymentsResponse {
statement_descriptor_suffix: item.statement_descriptor_suffix,
mandate_data: item.mandate_data,
..Default::default()
- }
+ })
}
}
@@ -759,12 +758,19 @@ pub enum SupportedWallets {
Gpay,
}
-#[derive(Debug, Default, serde::Deserialize, serde::Serialize, Clone)]
+#[derive(Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone)]
pub struct OrderDetails {
pub product_name: String,
pub quantity: u16,
}
+#[derive(Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone)]
+pub struct Metadata {
+ pub order_details: Option,
+ #[serde(flatten)]
+ pub data: serde_json::Value,
+}
+
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct PaymentsSessionRequest {
pub payment_id: String,
diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs
index ac62000882..437d18cfcf 100644
--- a/crates/router/src/compatibility/stripe/payment_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs
@@ -132,7 +132,7 @@ pub struct StripePaymentIntentRequest {
pub billing_details: Option,
pub statement_descriptor: Option,
pub statement_descriptor_suffix: Option,
- pub metadata: Option,
+ pub metadata: Option,
pub client_secret: Option>,
pub payment_method_options: Option,
}
@@ -277,6 +277,7 @@ pub struct StripePaymentIntentResponse {
pub customer: Option,
pub refunds: Option>,
pub mandate_id: Option,
+ pub metadata: Option,
}
impl From for StripePaymentIntentResponse {
@@ -294,6 +295,7 @@ impl From for StripePaymentIntentResponse {
id: resp.payment_id,
refunds: resp.refunds,
mandate_id: resp.mandate_id,
+ metadata: resp.metadata,
}
}
}
diff --git a/crates/router/src/compatibility/stripe/setup_intents/types.rs b/crates/router/src/compatibility/stripe/setup_intents/types.rs
index fad2fb2ec3..996af6c29f 100644
--- a/crates/router/src/compatibility/stripe/setup_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/setup_intents/types.rs
@@ -122,7 +122,7 @@ pub struct StripeSetupIntentRequest {
pub billing_details: Option,
pub statement_descriptor: Option,
pub statement_descriptor_suffix: Option,
- pub metadata: Option,
+ pub metadata: Option,
pub client_secret: Option>,
}
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 5c36a499c9..c37e344ea8 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -171,7 +171,7 @@ where
FData: Send,
Op: Operation + Send + Sync + Clone,
Req: Debug,
- Res: transformers::ToResponse, Op> + From,
+ Res: transformers::ToResponse, Op> + TryFrom,
// To create connector flow specific interface data
PaymentData: ConstructFlowSpecificData,
types::RouterData: Feature,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 86ef9aa31b..2a2fe20821 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -1,7 +1,7 @@
use std::marker::PhantomData;
use async_trait::async_trait;
-use common_utils::ext_traits::AsyncExt;
+use common_utils::ext_traits::{AsyncExt, Encode};
use error_stack::ResultExt;
use router_derive::PaymentOperation;
use router_env::{instrument, tracing};
@@ -143,7 +143,7 @@ impl GetTracker, api::PaymentsRequest> for Pa
request,
shipping_address.clone().map(|x| x.address_id),
billing_address.clone().map(|x| x.address_id),
- ),
+ )?,
storage_scheme,
)
.await
@@ -481,14 +481,21 @@ impl PaymentCreate {
request: &api::PaymentsRequest,
shipping_address_id: Option,
billing_address_id: Option,
- ) -> storage::PaymentIntentNew {
+ ) -> RouterResult {
let created_at @ modified_at @ last_synced = Some(common_utils::date_time::now());
let status =
helpers::payment_intent_status_fsm(&request.payment_method_data, request.confirm);
let client_secret =
crate::utils::generate_id(consts::ID_LENGTH, format!("{payment_id}_secret").as_str());
let (amount, currency) = (money.0, Some(money.1));
- storage::PaymentIntentNew {
+ let metadata = request
+ .metadata
+ .as_ref()
+ .map(|a| Encode::::encode_to_value(&a))
+ .transpose()
+ .change_context(errors::ApiErrorResponse::InternalServerError)
+ .attach_printable("Encoding Metadata to value failed")?;
+ Ok(storage::PaymentIntentNew {
payment_id: payment_id.to_string(),
merchant_id: merchant_id.to_string(),
status,
@@ -506,9 +513,9 @@ impl PaymentCreate {
billing_address_id,
statement_descriptor_name: request.statement_descriptor_name.clone(),
statement_descriptor_suffix: request.statement_descriptor_suffix.clone(),
- metadata: request.metadata.clone(),
+ metadata,
..storage::PaymentIntentNew::default()
- }
+ })
}
#[instrument(skip_all)]
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index 0fa67b6eee..9e7e8e80ea 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -103,7 +103,7 @@ where
pub trait ToResponse
where
- Self: From,
+ Self: TryFrom,
Op: Debug,
{
fn generate_response(
@@ -118,7 +118,7 @@ where
impl ToResponse, Op> for api::PaymentsResponse
where
- Self: From,
+ Self: TryFrom,
F: Clone,
Op: Debug,
{
@@ -233,7 +233,7 @@ pub fn payments_to_payments_response(
operation: Op,
) -> RouterResponse
where
- api::PaymentsResponse: From,
+ api::PaymentsResponse: TryFrom,
Op: Debug,
{
let currency = payment_attempt
@@ -256,7 +256,9 @@ where
.map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
services::BachResponse::Form(form)
} else {
- let mut response: api::PaymentsResponse = request.into();
+ let mut response: api::PaymentsResponse = request
+ .try_into()
+ .map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
let mut next_action_response = None;
if payment_intent.status == enums::IntentStatus::RequiresCustomerAction {
next_action_response = Some(api::NextAction {
@@ -406,7 +408,7 @@ impl TryFrom> for types::PaymentsAuthorizeData {
.transpose()
.unwrap_or_default();
- let order_details = parsed_metadata.map(|data| data.order_details);
+ let order_details = parsed_metadata.and_then(|data| data.order_details);
Ok(Self {
payment_method_data: {
@@ -504,7 +506,7 @@ impl TryFrom> for types::PaymentsSessionData {
.transpose()
.unwrap_or_default();
- let order_details = parsed_metadata.map(|data| data.order_details);
+ let order_details = parsed_metadata.and_then(|data| data.order_details);
Ok(Self {
amount: payment_data.amount.into(),