Skip to content

Commit

Permalink
feat: add support for sdk session call in v2
Browse files Browse the repository at this point in the history
  • Loading branch information
hrithikesh026 committed Nov 7, 2024
1 parent de69f4a commit bfd4a86
Show file tree
Hide file tree
Showing 16 changed files with 1,056 additions and 19 deletions.
1 change: 0 additions & 1 deletion crates/api_models/src/events/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@ impl ApiEventMetric for PaymentsManualUpdateResponse {
}
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsSessionResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
Expand Down
14 changes: 14 additions & 0 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5878,6 +5878,7 @@ pub struct ApplepayErrorResponse {
pub status_message: String,
}

#[cfg(feature = "v1")]
#[derive(Default, Debug, serde::Serialize, Clone, ToSchema)]
pub struct PaymentsSessionResponse {
/// The identifier for the payment
Expand All @@ -5890,6 +5891,19 @@ pub struct PaymentsSessionResponse {
pub session_token: Vec<SessionToken>,
}

#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct PaymentsSessionResponse {
/// The identifier for the payment
#[schema(value_type = String)]
pub payment_id: id_type::GlobalPaymentId,
/// This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK
#[schema(value_type = String)]
pub client_secret: Secret<common_utils::types::ClientSecret>,
/// The list of session token object
pub session_token: Vec<SessionToken>,
}

#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
pub struct PaymentRetrieveBody {
/// The identifier for the Merchant Account.
Expand Down
2 changes: 1 addition & 1 deletion crates/common_utils/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ mod client_secret_type {
Ok(row)
}
}

crate::impl_serializable_secret_id_type!(ClientSecret);
#[cfg(test)]
mod client_secret_tests {
#![allow(clippy::expect_used)]
Expand Down
22 changes: 19 additions & 3 deletions crates/diesel_models/src/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@ pub enum PaymentIntentUpdate {
status: storage_enums::IntentStatus,
updated_by: String,
},
/// Update the payment intent details on payment intent session token call, before calling the connector
MetadataUpdate {
metadata: masking::Secret<serde_json::Value>,
updated_by: String,
},
}

#[cfg(feature = "v1")]
Expand Down Expand Up @@ -518,7 +523,7 @@ pub struct PaymentIntentUpdateInternal {
// pub customer_id: Option<common_utils::id_type::CustomerId>,
// pub return_url: Option<>,
// pub setup_future_usage: Option<storage_enums::FutureUsage>,
// pub metadata: Option<pii::SecretSerdeValue>,
pub metadata: Option<pii::SecretSerdeValue>,
pub modified_at: PrimitiveDateTime,
// pub active_attempt_id: Option<String>,
// pub description: Option<String>,
Expand Down Expand Up @@ -592,7 +597,7 @@ impl PaymentIntentUpdate {
// customer_id,
// return_url,
// setup_future_usage,
// metadata,
metadata,
modified_at: _,
// active_attempt_id,
// description,
Expand All @@ -618,7 +623,7 @@ impl PaymentIntentUpdate {
// customer_id: customer_id.or(source.customer_id),
// return_url: return_url.or(source.return_url),
// setup_future_usage: setup_future_usage.or(source.setup_future_usage),
// metadata: metadata.or(source.metadata),
metadata: metadata.or(source.metadata),
modified_at: common_utils::date_time::now(),
// active_attempt_id: active_attempt_id.unwrap_or(source.active_attempt_id),
// description: description.or(source.description),
Expand Down Expand Up @@ -738,11 +743,22 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
PaymentIntentUpdate::ConfirmIntent { status, updated_by } => Self {
status: Some(status),
modified_at: common_utils::date_time::now(),
metadata: None,
updated_by,
},
PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => Self {
status: Some(status),
modified_at: common_utils::date_time::now(),
metadata: None,
updated_by,
},
PaymentIntentUpdate::MetadataUpdate {
metadata,
updated_by,
} => Self {
status: None,
modified_at: common_utils::date_time::now(),
metadata: Some(metadata),
updated_by,
},
}
Expand Down
4 changes: 3 additions & 1 deletion crates/hyperswitch_domain_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::marker::PhantomData;

#[cfg(feature = "v2")]
use api_models::payments::Address;
use api_models::payments::{Address, SessionToken};
use common_utils::{
self,
crypto::Encryptable,
Expand Down Expand Up @@ -509,6 +509,8 @@ where
{
pub flow: PhantomData<F>,
pub payment_intent: PaymentIntent,
pub email: Option<pii::Email>,
pub sessions_token: Vec<SessionToken>,
}

// TODO: Check if this can be merged with existing payment data
Expand Down
19 changes: 19 additions & 0 deletions crates/hyperswitch_domain_models/src/payments/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ pub enum PaymentIntentUpdate {
status: storage_enums::IntentStatus,
updated_by: String,
},
MetadataUpdate {
metadata: Secret<serde_json::Value>,
updated_by: String,
},
}

#[cfg(feature = "v2")]
Expand Down Expand Up @@ -373,6 +377,14 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
updated_by,
..Default::default()
},
PaymentIntentUpdate::MetadataUpdate {
metadata,
updated_by,
} => Self {
metadata: Some(metadata),
updated_by,
..Default::default()
},
}
}
}
Expand Down Expand Up @@ -588,6 +600,13 @@ impl From<PaymentIntentUpdate> for DieselPaymentIntentUpdate {
PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => {
Self::ConfirmIntentPostUpdate { status, updated_by }
}
PaymentIntentUpdate::MetadataUpdate {
metadata,
updated_by,
} => Self::MetadataUpdate {
metadata,
updated_by,
},
}
}
}
Expand Down
82 changes: 76 additions & 6 deletions crates/router/src/core/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub mod operations;
#[cfg(feature = "retry")]
pub mod retry;
pub mod routing;
#[cfg(feature = "v2")]
pub mod session_operation;
pub mod tokenization;
pub mod transformers;
pub mod types;
Expand Down Expand Up @@ -50,6 +52,8 @@ use router_env::{instrument, metrics::add_attributes, tracing};
#[cfg(feature = "olap")]
use router_types::transformers::ForeignFrom;
use scheduler::utils as pt_utils;
#[cfg(feature = "v2")]
pub use session_operation::payments_session_core;
#[cfg(feature = "olap")]
use strum::IntoEnumIterator;
use time;
Expand Down Expand Up @@ -172,7 +176,6 @@ where
.await
.to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
.attach_printable("Failed while fetching/creating customer")?;

let connector = get_connector_choice(
&operation,
state,
Expand All @@ -185,7 +188,6 @@ where
None,
)
.await?;

// TODO: do not use if let
let payment_data = if let Some(connector_call_type) = connector {
match connector_call_type {
Expand Down Expand Up @@ -2789,6 +2791,7 @@ where
)
.await?;

#[cfg(feature = "v1")]
payment_data.set_surcharge_details(session_surcharge_details.as_ref().and_then(
|session_surcharge_details| {
session_surcharge_details.fetch_surcharge_details(
Expand Down Expand Up @@ -3201,6 +3204,7 @@ pub fn is_preprocessing_required_for_wallets(connector_name: String) -> bool {
connector_name == *"trustpay" || connector_name == *"payme"
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub async fn construct_profile_id_and_get_mca<'a, F, D>(
state: &'a SessionState,
Expand All @@ -3215,7 +3219,6 @@ where
F: Clone,
D: OperationSessionGetters<F> + Send + Sync + Clone,
{
#[cfg(feature = "v1")]
let profile_id = payment_data
.get_payment_intent()
.profile_id
Expand All @@ -3242,6 +3245,37 @@ where
Ok(merchant_connector_account)
}

#[cfg(feature = "v2")]
#[instrument(skip_all)]
pub async fn construct_profile_id_and_get_mca<'a, F, D>(
state: &'a SessionState,
merchant_account: &domain::MerchantAccount,
payment_data: &D,
connector_name: &str,
merchant_connector_id: Option<&id_type::MerchantConnectorAccountId>,
key_store: &domain::MerchantKeyStore,
_should_validate: bool,
) -> RouterResult<helpers::MerchantConnectorAccountType>
where
F: Clone,
D: OperationSessionGetters<F> + Send + Sync + Clone,
{
let profile_id = payment_data.get_payment_intent().profile_id.clone();

let merchant_connector_account = helpers::get_merchant_connector_account(
state,
merchant_account.get_id(),
None,
key_store,
&profile_id,
connector_name,
merchant_connector_id,
)
.await?;

Ok(merchant_connector_account)
}

fn is_payment_method_tokenization_enabled_for_connector(
state: &SessionState,
connector_name: &str,
Expand Down Expand Up @@ -4439,7 +4473,43 @@ where
};
Ok(connector)
}
#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn get_connector_choice_for_sdk_session_token<F, Req, D>(
operation: &BoxedOperation<'_, F, Req, D>,
state: &SessionState,
req: &Req,
merchant_account: &domain::MerchantAccount,
_business_profile: &domain::Profile,
key_store: &domain::MerchantKeyStore,
payment_data: &mut D,
_eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
_mandate_type: Option<api::MandateTransactionType>,
) -> RouterResult<Option<ConnectorCallType>>
where
F: Send + Clone,
D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
let connector_choice = operation
.to_domain()?
.get_connector(
merchant_account,
&state.clone(),
req,
payment_data.get_payment_intent(),
key_store,
)
.await?;

let connector = Some(match connector_choice {
api::ConnectorChoice::SessionMultiple(connectors) => {
// todo perform session routing here
ConnectorCallType::SessionMultiple(connectors)
}
_ => return Err(errors::ApiErrorResponse::InternalServerError.into()),
});
Ok(connector)
}
async fn get_eligible_connector_for_nti<T: core_routing::GetRoutableConnectorsForChoice, F, D>(
state: &SessionState,
key_store: &domain::MerchantKeyStore,
Expand Down Expand Up @@ -6538,7 +6608,7 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentIntentData<F> {
}

fn get_sessions_token(&self) -> Vec<api::SessionToken> {
todo!()
self.sessions_token.clone()
}

fn get_token_data(&self) -> Option<&storage::PaymentTokenData> {
Expand Down Expand Up @@ -6589,8 +6659,8 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentIntentData<F> {
todo!()
}

fn push_sessions_token(&mut self, _token: api::SessionToken) {
todo!()
fn push_sessions_token(&mut self, token: api::SessionToken) {
self.sessions_token.push(token);
}

fn set_surcharge_details(&mut self, _surcharge_details: Option<types::SurchargeDetails>) {
Expand Down
46 changes: 46 additions & 0 deletions crates/router/src/core/payments/flows/session_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use common_utils::{
types::{AmountConvertor, StringMajorUnitForConnector},
};
use error_stack::{Report, ResultExt};
#[cfg(feature = "v2")]
use hyperswitch_domain_models::payments::PaymentIntentData;
use masking::ExposeInterface;
use router_env::metrics::add_attributes;

Expand All @@ -26,6 +28,50 @@ use crate::{
utils::OptionExt,
};

#[cfg(feature = "v2")]
#[async_trait]
impl
ConstructFlowSpecificData<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
for PaymentIntentData<api::Session>
{
async fn construct_router_data<'a>(
&self,
state: &routes::SessionState,
connector_id: &str,
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
customer: &Option<domain::Customer>,
merchant_connector_account: &helpers::MerchantConnectorAccountType,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
) -> RouterResult<types::PaymentsSessionRouterData> {
Box::pin(transformers::construct_payment_router_data_for_sdk_session(
state,
self.clone(),
connector_id,
merchant_account,
key_store,
customer,
merchant_connector_account,
merchant_recipient_data,
header_payload,
))
.await
}

async fn get_merchant_recipient_data<'a>(
&self,
_state: &routes::SessionState,
_merchant_account: &domain::MerchantAccount,
_key_store: &domain::MerchantKeyStore,
_merchant_connector_account: &helpers::MerchantConnectorAccountType,
_connector: &api::ConnectorData,
) -> RouterResult<Option<types::MerchantRecipientData>> {
Ok(None)
}
}

#[cfg(feature = "v1")]
#[async_trait]
impl
ConstructFlowSpecificData<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
Expand Down
Loading

0 comments on commit bfd4a86

Please sign in to comment.