mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(payments_v2): add payment_confirm_intent api endpoint (#6263)
Co-authored-by: hrithikesh026 <hrithikesh.vm@juspay.in> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: sai-harsha-vardhan <harsha111hero@gmail.com> Co-authored-by: Shankar Singh C <83439957+ShankarSinghC@users.noreply.github.com> Co-authored-by: spritianeja03 <146620839+spritianeja03@users.noreply.github.com> Co-authored-by: Spriti Aneja <spriti.aneja@juspay.in>
This commit is contained in:
@ -105,6 +105,15 @@ impl ApiEventMetric for id_type::PaymentId {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
impl ApiEventMetric for id_type::GlobalPaymentId {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
Some(ApiEventsType::Payment {
|
||||
payment_id: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Q: ApiEventMetric, E> ApiEventMetric for Result<Q, E> {
|
||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||
match self {
|
||||
|
||||
@ -27,7 +27,9 @@ use diesel::{
|
||||
};
|
||||
#[cfg(feature = "v2")]
|
||||
pub use global_id::{
|
||||
payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, refunds::GlobalRefundId,
|
||||
payment::{GlobalAttemptId, GlobalPaymentId},
|
||||
payment_methods::GlobalPaymentMethodId,
|
||||
refunds::GlobalRefundId,
|
||||
CellId,
|
||||
};
|
||||
pub use merchant::MerchantId;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
#![allow(unused)]
|
||||
pub mod payment;
|
||||
pub mod payment_methods;
|
||||
pub mod refunds;
|
||||
@ -24,6 +23,7 @@ pub(crate) struct GlobalId(LengthId<MAX_GLOBAL_ID_LENGTH, MIN_GLOBAL_ID_LENGTH>)
|
||||
pub(crate) enum GlobalEntity {
|
||||
Customer,
|
||||
Payment,
|
||||
Attempt,
|
||||
PaymentMethod,
|
||||
Refund,
|
||||
}
|
||||
@ -34,6 +34,7 @@ impl GlobalEntity {
|
||||
Self::Customer => "cus",
|
||||
Self::Payment => "pay",
|
||||
Self::PaymentMethod => "pm",
|
||||
Self::Attempt => "att",
|
||||
Self::Refund => "ref",
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,22 +2,16 @@ use error_stack::ResultExt;
|
||||
|
||||
use crate::{errors, generate_id_with_default_len, generate_time_ordered_id_without_prefix, types};
|
||||
|
||||
/// A global id that can be used to identify a payment
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
diesel::expression::AsExpression,
|
||||
)]
|
||||
#[diesel(sql_type = diesel::sql_types::Text)]
|
||||
pub struct GlobalPaymentId(super::GlobalId);
|
||||
crate::global_id_type!(
|
||||
GlobalPaymentId,
|
||||
"A global id that can be used to identify a payment
|
||||
The format will be `<cell_id>_<entity_prefix>_<time_ordered_id>`
|
||||
example - cell1_pay_uu1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p"
|
||||
);
|
||||
|
||||
// Database related implementations so that this field can be used directly in the database tables
|
||||
crate::impl_queryable_id_type!(GlobalPaymentId);
|
||||
crate::impl_to_sql_from_sql_global_id_type!(GlobalPaymentId);
|
||||
|
||||
impl GlobalPaymentId {
|
||||
/// Get string representation of the id
|
||||
@ -51,26 +45,24 @@ impl TryFrom<std::borrow::Cow<'static, str>> for GlobalPaymentId {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: refactor the macro to include this id use case as well
|
||||
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Text, DB> for GlobalPaymentId
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
super::GlobalId: diesel::serialize::ToSql<diesel::sql_types::Text, DB>,
|
||||
{
|
||||
fn to_sql<'b>(
|
||||
&'b self,
|
||||
out: &mut diesel::serialize::Output<'b, '_, DB>,
|
||||
) -> diesel::serialize::Result {
|
||||
self.0.to_sql(out)
|
||||
}
|
||||
}
|
||||
crate::global_id_type!(
|
||||
GlobalAttemptId,
|
||||
"A global id that can be used to identify a payment attempt"
|
||||
);
|
||||
|
||||
impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Text, DB> for GlobalPaymentId
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
super::GlobalId: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
|
||||
{
|
||||
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||
super::GlobalId::from_sql(value).map(Self)
|
||||
// Database related implementations so that this field can be used directly in the database tables
|
||||
crate::impl_queryable_id_type!(GlobalAttemptId);
|
||||
crate::impl_to_sql_from_sql_global_id_type!(GlobalAttemptId);
|
||||
|
||||
impl GlobalAttemptId {
|
||||
/// Generate a new GlobalAttemptId from a cell id
|
||||
pub fn generate(cell_id: &super::CellId) -> Self {
|
||||
let global_id = super::GlobalId::generate(cell_id.clone(), super::GlobalEntity::Attempt);
|
||||
Self(global_id)
|
||||
}
|
||||
|
||||
/// Get string representation of the id
|
||||
pub fn get_string_repr(&self) -> &str {
|
||||
self.0.get_string_repr()
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,6 +172,27 @@ mod id_type {
|
||||
};
|
||||
}
|
||||
|
||||
/// Defines a Global Id type
|
||||
#[cfg(feature = "v2")]
|
||||
#[macro_export]
|
||||
macro_rules! global_id_type {
|
||||
($type:ident, $doc:literal) => {
|
||||
#[doc = $doc]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
serde::Serialize,
|
||||
serde::Deserialize,
|
||||
diesel::expression::AsExpression,
|
||||
)]
|
||||
#[diesel(sql_type = diesel::sql_types::Text)]
|
||||
pub struct $type($crate::id_type::global_id::GlobalId);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements common methods on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_id_type_methods {
|
||||
@ -292,6 +313,40 @@ mod id_type {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
/// Implements the `ToSql` and `FromSql` traits on the specified Global ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_to_sql_from_sql_global_id_type {
|
||||
($type:ty, $diesel_type:ty) => {
|
||||
impl<DB> diesel::serialize::ToSql<$diesel_type, DB> for $type
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
$crate::id_type::global_id::GlobalId: diesel::serialize::ToSql<$diesel_type, DB>,
|
||||
{
|
||||
fn to_sql<'b>(
|
||||
&'b self,
|
||||
out: &mut diesel::serialize::Output<'b, '_, DB>,
|
||||
) -> diesel::serialize::Result {
|
||||
self.0.to_sql(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> diesel::deserialize::FromSql<$diesel_type, DB> for $type
|
||||
where
|
||||
DB: diesel::backend::Backend,
|
||||
$crate::id_type::global_id::GlobalId:
|
||||
diesel::deserialize::FromSql<$diesel_type, DB>,
|
||||
{
|
||||
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||
$crate::id_type::global_id::GlobalId::from_sql(value).map(Self)
|
||||
}
|
||||
}
|
||||
};
|
||||
($type:ty) => {
|
||||
$crate::impl_to_sql_from_sql_global_id_type!($type, diesel::sql_types::Text);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements the `Queryable` trait on the specified ID type.
|
||||
#[macro_export]
|
||||
macro_rules! impl_queryable_id_type {
|
||||
|
||||
@ -603,6 +603,13 @@ impl StringMajorUnit {
|
||||
/// This domain type can be used for any url
|
||||
pub struct Url(url::Url);
|
||||
|
||||
impl Url {
|
||||
/// Get string representation of the url
|
||||
pub fn get_string_repr(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> ToSql<sql_types::Text, DB> for Url
|
||||
where
|
||||
DB: Backend,
|
||||
@ -667,6 +674,30 @@ mod client_secret_type {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ClientSecret {
|
||||
type Err = ParsingError;
|
||||
|
||||
fn from_str(str_value: &str) -> Result<Self, Self::Err> {
|
||||
let (payment_id, secret) =
|
||||
str_value
|
||||
.rsplit_once("_secret_")
|
||||
.ok_or(ParsingError::EncodeError(
|
||||
"Expected a string in the format '{payment_id}_secret_{secret}'",
|
||||
))?;
|
||||
|
||||
let payment_id = id_type::GlobalPaymentId::try_from(Cow::Owned(payment_id.to_owned()))
|
||||
.map_err(|err| {
|
||||
logger::error!(global_payment_id_error=?err);
|
||||
ParsingError::EncodeError("Error while constructing GlobalPaymentId")
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
payment_id,
|
||||
secret: masking::Secret::new(secret.to_owned()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ClientSecret {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
@ -1096,6 +1127,12 @@ impl Description {
|
||||
pub fn from_str_unchecked(input_str: &'static str) -> Self {
|
||||
Self(LengthString::new_unchecked(input_str.to_owned()))
|
||||
}
|
||||
|
||||
// TODO: Remove this function in future once description in router data is updated to domain type
|
||||
/// Get the string representation of the description
|
||||
pub fn get_string_repr(&self) -> &str {
|
||||
&self.0 .0
|
||||
}
|
||||
}
|
||||
|
||||
/// Domain type for Statement Descriptor
|
||||
@ -1273,6 +1310,58 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
/// Browser information to be used for 3DS 2.0
|
||||
// If any of the field is PII, then we can make them as secret
|
||||
#[derive(
|
||||
ToSchema,
|
||||
Debug,
|
||||
Clone,
|
||||
serde::Deserialize,
|
||||
serde::Serialize,
|
||||
Eq,
|
||||
PartialEq,
|
||||
diesel::AsExpression,
|
||||
)]
|
||||
#[diesel(sql_type = Jsonb)]
|
||||
pub struct BrowserInformation {
|
||||
/// Color depth supported by the browser
|
||||
pub color_depth: Option<u8>,
|
||||
|
||||
/// Whether java is enabled in the browser
|
||||
pub java_enabled: Option<bool>,
|
||||
|
||||
/// Whether javascript is enabled in the browser
|
||||
pub java_script_enabled: Option<bool>,
|
||||
|
||||
/// Language supported
|
||||
pub language: Option<String>,
|
||||
|
||||
/// The screen height in pixels
|
||||
pub screen_height: Option<u32>,
|
||||
|
||||
/// The screen width in pixels
|
||||
pub screen_width: Option<u32>,
|
||||
|
||||
/// Time zone of the client
|
||||
pub time_zone: Option<i32>,
|
||||
|
||||
/// Ip address of the client
|
||||
#[schema(value_type = Option<String>)]
|
||||
pub ip_address: Option<std::net::IpAddr>,
|
||||
|
||||
/// List of headers that are accepted
|
||||
#[schema(
|
||||
example = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
|
||||
)]
|
||||
pub accept_header: Option<String>,
|
||||
|
||||
/// User-agent of the browser
|
||||
pub user_agent: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
crate::impl_to_sql_from_sql_json!(BrowserInformation);
|
||||
/// Domain type for connector_transaction_id
|
||||
/// Maximum length for connector's transaction_id can be 128 characters in HS DB.
|
||||
/// In case connector's use an identifier whose length exceeds 128 characters,
|
||||
|
||||
Reference in New Issue
Block a user