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(),