revert(order_details): revert back order_details to be an object, and removing meta_data from PaymentIntent (#1279)

This commit is contained in:
rishavkar
2023-05-26 13:19:33 +05:30
committed by GitHub
parent e78b3a65d4
commit 597ec16907
16 changed files with 56 additions and 114 deletions

View File

@ -1562,14 +1562,12 @@ pub struct OrderDetails {
/// The quantity of the product to be purchased /// The quantity of the product to be purchased
#[schema(example = 1)] #[schema(example = 1)]
pub quantity: u16, pub quantity: u16,
/// the amount per quantity of product
pub amount: i64,
} }
#[derive(Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)] #[derive(Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
pub struct Metadata { pub struct Metadata {
/// Information about the product and quantity for specific connectors. (e.g. Klarna) /// Information about the product and quantity for specific connectors. (e.g. Klarna)
pub order_details: Option<Vec<OrderDetails>>, pub order_details: Option<OrderDetails>,
/// Information used for routing /// Information used for routing
pub routing_parameters: Option<HashMap<String, String>>, pub routing_parameters: Option<HashMap<String, String>>,
/// Any other metadata that is to be provided /// Any other metadata that is to be provided

View File

@ -896,31 +896,18 @@ fn get_address_info(address: Option<&api_models::payments::Address>) -> Option<A
} }
fn get_line_items(item: &types::PaymentsAuthorizeRouterData) -> Vec<LineItem> { fn get_line_items(item: &types::PaymentsAuthorizeRouterData) -> Vec<LineItem> {
let order_details = item.request.order_details.clone(); let order_details = item.request.order_details.as_ref();
match order_details {
Some(od) => od
.iter()
.map(|data| LineItem {
amount_including_tax: Some(item.request.amount),
amount_excluding_tax: Some(item.request.amount),
description: Some(data.product_name.clone()),
id: Some(String::from("Items #1")),
tax_amount: None,
quantity: Some(data.quantity),
})
.collect(),
None => {
let line_item = LineItem { let line_item = LineItem {
amount_including_tax: Some(item.request.amount), amount_including_tax: Some(item.request.amount),
amount_excluding_tax: Some(item.request.amount), amount_excluding_tax: Some(item.request.amount),
description: None, description: order_details.map(|details| details.product_name.clone()),
// We support only one product details in payment request as of now, therefore hard coded the id.
// If we begin to support multiple product details in future then this logic should be made to create ID dynamically
id: Some(String::from("Items #1")), id: Some(String::from("Items #1")),
tax_amount: None, tax_amount: None,
quantity: Some(1), quantity: Some(order_details.map_or(1, |details| details.quantity)),
}; };
vec![line_item] vec![line_item]
}
}
} }
fn get_telephone_number(item: &types::PaymentsAuthorizeRouterData) -> Option<Secret<String>> { fn get_telephone_number(item: &types::PaymentsAuthorizeRouterData) -> Option<Secret<String>> {

View File

@ -48,15 +48,12 @@ impl TryFrom<&types::PaymentsSessionRouterData> for KlarnaSessionRequest {
purchase_currency: request.currency, purchase_currency: request.currency,
order_amount: request.amount, order_amount: request.amount,
locale: "en-US".to_string(), locale: "en-US".to_string(),
order_lines: order_details order_lines: vec![OrderLines {
.iter() name: order_details.product_name,
.map(|data| OrderLines { quantity: order_details.quantity,
name: data.product_name.clone(), unit_price: request.amount,
quantity: data.quantity, total_amount: request.amount,
unit_price: data.amount, }],
total_amount: i64::from(data.quantity) * (data.amount),
})
.collect(),
}), }),
None => Err(report!(errors::ConnectorError::MissingRequiredField { None => Err(report!(errors::ConnectorError::MissingRequiredField {
field_name: "product_name", field_name: "product_name",
@ -96,15 +93,12 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for KlarnaPaymentsRequest {
purchase_country: "US".to_string(), purchase_country: "US".to_string(),
purchase_currency: request.currency, purchase_currency: request.currency,
order_amount: request.amount, order_amount: request.amount,
order_lines: order_details order_lines: vec![OrderLines {
.iter() name: order_details.product_name,
.map(|data| OrderLines { quantity: order_details.quantity,
name: data.product_name.clone(), unit_price: request.amount,
quantity: data.quantity, total_amount: request.amount,
unit_price: data.amount, }],
total_amount: i64::from(data.quantity) * (data.amount),
})
.collect(),
}), }),
None => Err(report!(errors::ConnectorError::MissingRequiredField { None => Err(report!(errors::ConnectorError::MissingRequiredField {
field_name: "product_name" field_name: "product_name"

View File

@ -173,7 +173,7 @@ pub trait PaymentsAuthorizeRequestData {
fn is_auto_capture(&self) -> Result<bool, Error>; fn is_auto_capture(&self) -> Result<bool, Error>;
fn get_email(&self) -> Result<Email, Error>; fn get_email(&self) -> Result<Email, Error>;
fn get_browser_info(&self) -> Result<types::BrowserInformation, Error>; fn get_browser_info(&self) -> Result<types::BrowserInformation, Error>;
fn get_order_details(&self) -> Result<Vec<OrderDetails>, Error>; fn get_order_details(&self) -> Result<OrderDetails, Error>;
fn get_card(&self) -> Result<api::Card, Error>; fn get_card(&self) -> Result<api::Card, Error>;
fn get_return_url(&self) -> Result<String, Error>; fn get_return_url(&self) -> Result<String, Error>;
fn connector_mandate_id(&self) -> Option<String>; fn connector_mandate_id(&self) -> Option<String>;
@ -200,7 +200,7 @@ impl PaymentsAuthorizeRequestData for types::PaymentsAuthorizeData {
.clone() .clone()
.ok_or_else(missing_field_err("browser_info")) .ok_or_else(missing_field_err("browser_info"))
} }
fn get_order_details(&self) -> Result<Vec<OrderDetails>, Error> { fn get_order_details(&self) -> Result<OrderDetails, Error> {
self.order_details self.order_details
.clone() .clone()
.ok_or_else(missing_field_err("order_details")) .ok_or_else(missing_field_err("order_details"))

View File

@ -204,15 +204,12 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for ZenPaymentsRequest {
ip, ip,
}, },
custom_ipn_url: item.request.get_webhook_url()?, custom_ipn_url: item.request.get_webhook_url()?,
items: order_details items: vec![ZenItemObject {
.iter() name: order_details.product_name,
.map(|data| ZenItemObject { price: order_amount.clone(),
name: data.product_name.clone(), quantity: 1,
quantity: data.quantity, line_amount_total: order_amount,
price: data.amount.to_string(), }],
line_amount_total: order_amount.clone(),
})
.collect(),
}) })
} }
} }

View File

@ -1431,7 +1431,6 @@ mod tests {
active_attempt_id: "nopes".to_string(), active_attempt_id: "nopes".to_string(),
business_country: storage_enums::CountryAlpha2::AG, business_country: storage_enums::CountryAlpha2::AG,
business_label: "no".to_string(), business_label: "no".to_string(),
meta_data: None,
}; };
let req_cs = Some("1".to_string()); let req_cs = Some("1".to_string());
let merchant_fulfillment_time = Some(900); let merchant_fulfillment_time = Some(900);
@ -1471,7 +1470,6 @@ mod tests {
active_attempt_id: "nopes".to_string(), active_attempt_id: "nopes".to_string(),
business_country: storage_enums::CountryAlpha2::AG, business_country: storage_enums::CountryAlpha2::AG,
business_label: "no".to_string(), business_label: "no".to_string(),
meta_data: None,
}; };
let req_cs = Some("1".to_string()); let req_cs = Some("1".to_string());
let merchant_fulfillment_time = Some(10); let merchant_fulfillment_time = Some(10);
@ -1511,7 +1509,6 @@ mod tests {
active_attempt_id: "nopes".to_string(), active_attempt_id: "nopes".to_string(),
business_country: storage_enums::CountryAlpha2::AG, business_country: storage_enums::CountryAlpha2::AG,
business_label: "no".to_string(), business_label: "no".to_string(),
meta_data: None,
}; };
let req_cs = Some("1".to_string()); let req_cs = Some("1".to_string());
let merchant_fulfillment_time = Some(10); let merchant_fulfillment_time = Some(10);

View File

@ -3,7 +3,6 @@ use std::marker::PhantomData;
use async_trait::async_trait; use async_trait::async_trait;
use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; use common_utils::ext_traits::{AsyncExt, Encode, ValueExt};
use error_stack::{self, ResultExt}; use error_stack::{self, ResultExt};
use masking::Secret;
use router_derive::PaymentOperation; use router_derive::PaymentOperation;
use router_env::{instrument, tracing}; use router_env::{instrument, tracing};
use storage_models::ephemeral_key; use storage_models::ephemeral_key;
@ -545,7 +544,6 @@ impl PaymentCreate {
.transpose() .transpose()
.change_context(errors::ApiErrorResponse::InternalServerError) .change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Encoding Metadata to value failed")?; .attach_printable("Encoding Metadata to value failed")?;
let meta_data = metadata.clone().map(Secret::new);
let (business_country, business_label) = helpers::get_business_details( let (business_country, business_label) = helpers::get_business_details(
request.business_country, request.business_country,
@ -575,7 +573,6 @@ impl PaymentCreate {
business_country, business_country,
business_label, business_label,
active_attempt_id, active_attempt_id,
meta_data,
..storage::PaymentIntentNew::default() ..storage::PaymentIntentNew::default()
}) })
} }

View File

@ -196,20 +196,16 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsSessionRequest> for
F: 'b + Send, F: 'b + Send,
{ {
let metadata = payment_data.payment_intent.metadata.clone(); let metadata = payment_data.payment_intent.metadata.clone();
let meta_data = payment_data.payment_intent.meta_data.clone(); payment_data.payment_intent = match metadata {
payment_data.payment_intent = match (metadata, meta_data) { Some(metadata) => db
(Some(metadata), Some(meta_data)) => db
.update_payment_intent( .update_payment_intent(
payment_data.payment_intent, payment_data.payment_intent,
storage::PaymentIntentUpdate::MetadataUpdate { storage::PaymentIntentUpdate::MetadataUpdate { metadata },
metadata,
meta_data,
},
storage_scheme, storage_scheme,
) )
.await .await
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?, .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?,
_ => payment_data.payment_intent, None => payment_data.payment_intent,
}; };
Ok((Box::new(self), payment_data)) Ok((Box::new(self), payment_data))

View File

@ -593,14 +593,14 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
let parsed_metadata: Option<api_models::payments::Metadata> = payment_data let parsed_metadata: Option<api_models::payments::Metadata> = payment_data
.payment_intent .payment_intent
.meta_data .metadata
.map(|metadata_value| { .map(|metadata_value| {
metadata_value metadata_value
.parse_value("meta_data") .parse_value("metadata")
.change_context(errors::ApiErrorResponse::InvalidDataValue { .change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "meta_data", field_name: "metadata",
}) })
.attach_printable("unable to parse meta_data") .attach_printable("unable to parse metadata")
}) })
.transpose() .transpose()
.unwrap_or_default(); .unwrap_or_default();
@ -764,14 +764,14 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionD
let payment_data = additional_data.payment_data; let payment_data = additional_data.payment_data;
let parsed_metadata: Option<api_models::payments::Metadata> = payment_data let parsed_metadata: Option<api_models::payments::Metadata> = payment_data
.payment_intent .payment_intent
.meta_data .metadata
.map(|metadata_value| { .map(|metadata_value| {
metadata_value metadata_value
.parse_value("meta_data") .parse_value("metadata")
.change_context(errors::ApiErrorResponse::InvalidDataValue { .change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "meta_data", field_name: "metadata",
}) })
.attach_printable("unable to parse meta_data") .attach_printable("unable to parse metadata")
}) })
.transpose() .transpose()
.unwrap_or_default(); .unwrap_or_default();

View File

@ -95,7 +95,6 @@ mod storage {
business_country: new.business_country, business_country: new.business_country,
business_label: new.business_label.clone(), business_label: new.business_label.clone(),
active_attempt_id: new.active_attempt_id.to_owned(), active_attempt_id: new.active_attempt_id.to_owned(),
meta_data: new.meta_data.clone(),
}; };
match self match self
@ -354,7 +353,6 @@ impl PaymentIntentInterface for MockDb {
business_country: new.business_country, business_country: new.business_country,
business_label: new.business_label, business_label: new.business_label,
active_attempt_id: new.active_attempt_id.to_owned(), active_attempt_id: new.active_attempt_id.to_owned(),
meta_data: new.meta_data,
}; };
payment_intents.push(payment_intent.clone()); payment_intents.push(payment_intent.clone());
Ok(payment_intent) Ok(payment_intent)

View File

@ -224,7 +224,7 @@ pub struct PaymentsAuthorizeData {
pub off_session: Option<bool>, pub off_session: Option<bool>,
pub setup_mandate_details: Option<payments::MandateData>, pub setup_mandate_details: Option<payments::MandateData>,
pub browser_info: Option<BrowserInformation>, pub browser_info: Option<BrowserInformation>,
pub order_details: Option<Vec<api_models::payments::OrderDetails>>, pub order_details: Option<api_models::payments::OrderDetails>,
pub session_token: Option<String>, pub session_token: Option<String>,
pub enrolled_for_3ds: bool, pub enrolled_for_3ds: bool,
pub related_transaction_id: Option<String>, pub related_transaction_id: Option<String>,
@ -314,7 +314,7 @@ pub struct PaymentsSessionData {
pub amount: i64, pub amount: i64,
pub currency: storage_enums::Currency, pub currency: storage_enums::Currency,
pub country: Option<api::enums::CountryAlpha2>, pub country: Option<api::enums::CountryAlpha2>,
pub order_details: Option<Vec<api_models::payments::OrderDetails>>, pub order_details: Option<api_models::payments::OrderDetails>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -306,11 +306,10 @@ async fn should_fail_payment_for_incorrect_card_number() {
card_number: CardNumber::from_str("1234567891011").unwrap(), card_number: CardNumber::from_str("1234567891011").unwrap(),
..utils::CCardType::default().0 ..utils::CCardType::default().0
}), }),
order_details: Some(vec![OrderDetails { order_details: Some(OrderDetails {
product_name: "test".to_string(), product_name: "test".to_string(),
quantity: 1, quantity: 1,
amount: 1000, }),
}]),
email: Some(Email::from_str("test@gmail.com").unwrap()), email: Some(Email::from_str("test@gmail.com").unwrap()),
webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
..utils::PaymentAuthorizeType::default().0 ..utils::PaymentAuthorizeType::default().0
@ -341,11 +340,10 @@ async fn should_fail_payment_for_incorrect_cvc() {
card_cvc: Secret::new("12345".to_string()), card_cvc: Secret::new("12345".to_string()),
..utils::CCardType::default().0 ..utils::CCardType::default().0
}), }),
order_details: Some(vec![OrderDetails { order_details: Some(OrderDetails {
product_name: "test".to_string(), product_name: "test".to_string(),
quantity: 1, quantity: 1,
amount: 1000, }),
}]),
email: Some(Email::from_str("test@gmail.com").unwrap()), email: Some(Email::from_str("test@gmail.com").unwrap()),
webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
..utils::PaymentAuthorizeType::default().0 ..utils::PaymentAuthorizeType::default().0
@ -376,11 +374,10 @@ async fn should_fail_payment_for_invalid_exp_month() {
card_exp_month: Secret::new("20".to_string()), card_exp_month: Secret::new("20".to_string()),
..utils::CCardType::default().0 ..utils::CCardType::default().0
}), }),
order_details: Some(vec![OrderDetails { order_details: Some(OrderDetails {
product_name: "test".to_string(), product_name: "test".to_string(),
quantity: 1, quantity: 1,
amount: 1000, }),
}]),
email: Some(Email::from_str("test@gmail.com").unwrap()), email: Some(Email::from_str("test@gmail.com").unwrap()),
webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
..utils::PaymentAuthorizeType::default().0 ..utils::PaymentAuthorizeType::default().0
@ -411,11 +408,10 @@ async fn should_fail_payment_for_incorrect_expiry_year() {
card_exp_year: Secret::new("2000".to_string()), card_exp_year: Secret::new("2000".to_string()),
..utils::CCardType::default().0 ..utils::CCardType::default().0
}), }),
order_details: Some(vec![OrderDetails { order_details: Some(OrderDetails {
product_name: "test".to_string(), product_name: "test".to_string(),
quantity: 1, quantity: 1,
amount: 1000, }),
}]),
email: Some(Email::from_str("test@gmail.com").unwrap()), email: Some(Email::from_str("test@gmail.com").unwrap()),
webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()), webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
..utils::PaymentAuthorizeType::default().0 ..utils::PaymentAuthorizeType::default().0

View File

@ -36,7 +36,6 @@ pub struct PaymentIntent {
pub active_attempt_id: String, pub active_attempt_id: String,
pub business_country: storage_enums::CountryAlpha2, pub business_country: storage_enums::CountryAlpha2,
pub business_label: String, pub business_label: String,
pub meta_data: Option<pii::SecretSerdeValue>,
} }
#[derive( #[derive(
@ -79,7 +78,6 @@ pub struct PaymentIntentNew {
pub active_attempt_id: String, pub active_attempt_id: String,
pub business_country: storage_enums::CountryAlpha2, pub business_country: storage_enums::CountryAlpha2,
pub business_label: String, pub business_label: String,
pub meta_data: Option<pii::SecretSerdeValue>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -91,7 +89,6 @@ pub enum PaymentIntentUpdate {
}, },
MetadataUpdate { MetadataUpdate {
metadata: pii::SecretSerdeValue, metadata: pii::SecretSerdeValue,
meta_data: pii::SecretSerdeValue,
}, },
ReturnUrlUpdate { ReturnUrlUpdate {
return_url: Option<String>, return_url: Option<String>,
@ -149,7 +146,6 @@ pub struct PaymentIntentUpdateInternal {
pub active_attempt_id: Option<String>, pub active_attempt_id: Option<String>,
pub business_country: Option<storage_enums::CountryAlpha2>, pub business_country: Option<storage_enums::CountryAlpha2>,
pub business_label: Option<String>, pub business_label: Option<String>,
pub meta_data: Option<pii::SecretSerdeValue>,
} }
impl PaymentIntentUpdate { impl PaymentIntentUpdate {
@ -177,7 +173,6 @@ impl PaymentIntentUpdate {
.shipping_address_id .shipping_address_id
.or(source.shipping_address_id), .or(source.shipping_address_id),
modified_at: common_utils::date_time::now(), modified_at: common_utils::date_time::now(),
meta_data: internal_update.meta_data.or(source.meta_data),
..source ..source
} }
} }
@ -212,12 +207,8 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
business_label, business_label,
..Default::default() ..Default::default()
}, },
PaymentIntentUpdate::MetadataUpdate { PaymentIntentUpdate::MetadataUpdate { metadata } => Self {
metadata,
meta_data,
} => Self {
metadata: Some(metadata), metadata: Some(metadata),
meta_data: Some(meta_data),
modified_at: Some(common_utils::date_time::now()), modified_at: Some(common_utils::date_time::now()),
..Default::default() ..Default::default()
}, },

View File

@ -356,7 +356,6 @@ diesel::table! {
active_attempt_id -> Varchar, active_attempt_id -> Varchar,
business_country -> CountryAlpha2, business_country -> CountryAlpha2,
business_label -> Varchar, business_label -> Varchar,
meta_data -> Nullable<Jsonb>,
} }
} }

View File

@ -1 +0,0 @@
ALTER TABLE payment_intent DROP COLUMN meta_data;

View File

@ -1,7 +0,0 @@
ALTER TABLE payment_intent ADD COLUMN meta_data jsonb;
UPDATE payment_intent SET meta_data = metadata;
UPDATE payment_intent SET meta_data = jsonb_set(meta_data, '{order_details}', to_jsonb(ARRAY(select metadata -> 'order_details')), true);