refactor(core): query business profile only once (#2830)

This commit is contained in:
Narayan Bhat
2023-11-20 18:19:19 +05:30
committed by GitHub
parent 39540015fd
commit 44deeb7e76
13 changed files with 770 additions and 577 deletions

View File

@ -31,9 +31,8 @@ use scheduler::{db::process_tracker::ProcessTrackerExt, errors as sch_errors, ut
use time;
pub use self::operations::{
PaymentApprove, PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate,
PaymentMethodValidate, PaymentReject, PaymentResponse, PaymentSession, PaymentStatus,
PaymentUpdate,
PaymentApprove, PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate, PaymentReject,
PaymentResponse, PaymentSession, PaymentStatus, PaymentUpdate,
};
use self::{
flows::{ConstructFlowSpecificData, Feature},
@ -112,7 +111,12 @@ where
tracing::Span::current().record("payment_id", &format!("{}", validate_result.payment_id));
let (operation, mut payment_data, customer_details) = operation
let operations::GetTrackerResponse {
operation,
customer_details,
mut payment_data,
business_profile,
} = operation
.to_get_tracker()?
.get_trackers(
state,
@ -142,6 +146,7 @@ where
state,
&req,
&merchant_account,
&business_profile,
&key_store,
&mut payment_data,
eligible_connectors,
@ -1998,11 +2003,13 @@ where
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub async fn get_connector_choice<F, Req, Ctx>(
operation: &BoxedOperation<'_, F, Req, Ctx>,
state: &AppState,
req: &Req,
merchant_account: &domain::MerchantAccount,
business_profile: &storage::business_profile::BusinessProfile,
key_store: &domain::MerchantKeyStore,
payment_data: &mut PaymentData<F>,
eligible_connectors: Option<Vec<api_models::enums::RoutableConnectors>>,
@ -2040,6 +2047,7 @@ where
connector_selection(
state,
merchant_account,
business_profile,
key_store,
payment_data,
Some(straight_through),
@ -2052,6 +2060,7 @@ where
connector_selection(
state,
merchant_account,
business_profile,
key_store,
payment_data,
None,
@ -2075,6 +2084,7 @@ where
pub async fn connector_selection<F>(
state: &AppState,
merchant_account: &domain::MerchantAccount,
business_profile: &storage::business_profile::BusinessProfile,
key_store: &domain::MerchantKeyStore,
payment_data: &mut PaymentData<F>,
request_straight_through: Option<serde_json::Value>,
@ -2114,6 +2124,7 @@ where
let decided_connector = decide_connector(
state.clone(),
merchant_account,
business_profile,
key_store,
payment_data,
request_straight_through,
@ -2141,9 +2152,11 @@ where
Ok(decided_connector)
}
#[allow(clippy::too_many_arguments)]
pub async fn decide_connector<F>(
state: AppState,
merchant_account: &domain::MerchantAccount,
business_profile: &storage::business_profile::BusinessProfile,
key_store: &domain::MerchantKeyStore,
payment_data: &mut PaymentData<F>,
request_straight_through: Option<api::routing::StraightThroughAlgorithm>,
@ -2345,6 +2358,7 @@ where
route_connector_v1(
&state,
merchant_account,
business_profile,
key_store,
payment_data,
routing_data,
@ -2480,6 +2494,7 @@ where
pub async fn route_connector_v1<F>(
state: &AppState,
merchant_account: &domain::MerchantAccount,
business_profile: &storage::business_profile::BusinessProfile,
key_store: &domain::MerchantKeyStore,
payment_data: &mut PaymentData<F>,
routing_data: &mut storage::RoutingData,
@ -2488,44 +2503,19 @@ pub async fn route_connector_v1<F>(
where
F: Send + Clone,
{
#[cfg(not(feature = "business_profile_routing"))]
let algorithm_ref: api::routing::RoutingAlgorithmRef = merchant_account
.routing_algorithm
.clone()
.map(|ra| ra.parse_value("RoutingAlgorithmRef"))
let routing_algorithm = if cfg!(feature = "business_profile_routing") {
business_profile.routing_algorithm.clone()
} else {
merchant_account.routing_algorithm.clone()
};
let algorithm_ref = routing_algorithm
.map(|ra| ra.parse_value::<api::routing::RoutingAlgorithmRef>("RoutingAlgorithmRef"))
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Could not decode merchant routing algorithm ref")?
.unwrap_or_default();
#[cfg(feature = "business_profile_routing")]
let algorithm_ref: api::routing::RoutingAlgorithmRef = {
let profile_id = payment_data
.payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = state
.store
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
business_profile
.routing_algorithm
.clone()
.map(|ra| ra.parse_value("RoutingAlgorithmRef"))
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Could not decode merchant routing algorithm ref")?
.unwrap_or_default()
};
let connectors = routing::perform_static_routing_v1(
state,
&merchant_account.merchant_id,

View File

@ -4,7 +4,6 @@ pub mod payment_capture;
pub mod payment_complete_authorize;
pub mod payment_confirm;
pub mod payment_create;
pub mod payment_method_validate;
pub mod payment_reject;
pub mod payment_response;
pub mod payment_session;
@ -20,10 +19,9 @@ use router_env::{instrument, tracing};
pub use self::{
payment_approve::PaymentApprove, payment_cancel::PaymentCancel,
payment_capture::PaymentCapture, payment_confirm::PaymentConfirm,
payment_create::PaymentCreate, payment_method_validate::PaymentMethodValidate,
payment_reject::PaymentReject, payment_response::PaymentResponse,
payment_session::PaymentSession, payment_start::PaymentStart, payment_status::PaymentStatus,
payment_update::PaymentUpdate,
payment_create::PaymentCreate, payment_reject::PaymentReject,
payment_response::PaymentResponse, payment_session::PaymentSession,
payment_start::PaymentStart, payment_status::PaymentStatus, payment_update::PaymentUpdate,
};
use super::{helpers, CustomerDetails, PaymentData};
use crate::{
@ -91,8 +89,15 @@ pub trait ValidateRequest<F, R, Ctx: PaymentMethodRetrieve> {
) -> RouterResult<(BoxedOperation<'b, F, R, Ctx>, ValidateResult<'a>)>;
}
pub struct GetTrackerResponse<'a, F: Clone, R, Ctx> {
pub operation: BoxedOperation<'a, F, R, Ctx>,
pub customer_details: Option<CustomerDetails>,
pub payment_data: PaymentData<F>,
pub business_profile: storage::business_profile::BusinessProfile,
}
#[async_trait]
pub trait GetTracker<F, D, R, Ctx: PaymentMethodRetrieve>: Send {
pub trait GetTracker<F: Clone, D, R, Ctx: PaymentMethodRetrieve>: Send {
#[allow(clippy::too_many_arguments)]
async fn get_trackers<'a>(
&'a self,
@ -103,7 +108,7 @@ pub trait GetTracker<F, D, R, Ctx: PaymentMethodRetrieve>: Send {
merchant_account: &domain::MerchantAccount,
mechant_key_store: &domain::MerchantKeyStore,
auth_flow: services::AuthFlow,
) -> RouterResult<(BoxedOperation<'a, F, R, Ctx>, D, Option<CustomerDetails>)>;
) -> RouterResult<GetTrackerResponse<'a, F, R, Ctx>>;
}
#[async_trait]

View File

@ -45,11 +45,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRequest, Ctx>> {
let db = &*state.store;
let merchant_id = &merchant_account.merchant_id;
let storage_scheme = merchant_account.storage_scheme;
@ -76,6 +72,21 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
"confirm",
)?;
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = state
.store
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let (
token,
payment_method,
@ -207,50 +218,57 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
format!("Error while retrieving frm_response, merchant_id: {}, payment_id: {attempt_id}", &merchant_account.merchant_id)
});
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id: None,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response,
surcharge_details: None,
frm_message: frm_response.ok(),
payment_link_data: None,
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id: None,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(CustomerDetails {
customer_id: request.customer_id.clone(),
name: request.name.clone(),
email: request.email.clone(),
phone: request.phone.clone(),
phone_country_code: request.phone_country_code.clone(),
}),
))
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response,
surcharge_details: None,
frm_message: frm_response.ok(),
payment_link_data: None,
};
let customer_details = Some(CustomerDetails {
customer_id: request.customer_id.clone(),
name: request.name.clone(),
email: request.email.clone(),
phone: request.phone.clone(),
phone_country_code: request.phone_country_code.clone(),
});
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details,
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -12,7 +12,7 @@ use crate::{
core::{
errors::{self, RouterResult, StorageErrorExt},
payment_methods::PaymentMethodRetrieve,
payments::{helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
payments::{helpers, operations, PaymentAddress, PaymentData},
},
routes::AppState,
services,
@ -42,11 +42,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsCancelRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsCancelRequest, Ctx>> {
let db = &*state.store;
let merchant_id = &merchant_account.merchant_id;
let storage_scheme = merchant_account.storage_scheme;
@ -128,45 +124,63 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
.await
.transpose()?;
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: None,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: None,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: None,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
None,
))
confirm: None,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details: None,
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -41,11 +41,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsCaptureRequest, Ctx>,
payments::PaymentData<F>,
Option<payments::CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsCaptureRequest, Ctx>> {
let db = &*state.store;
let merchant_id = &merchant_account.merchant_id;
let storage_scheme = merchant_account.storage_scheme;
@ -172,44 +168,63 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
.await
.transpose()?;
Ok((
Box::new(self),
payments::PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
force_sync: None,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: None,
address: payments::PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: None,
payment_method_data: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = payments::PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
force_sync: None,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: None,
address: payments::PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
None,
))
confirm: None,
payment_method_data: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details: None,
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -44,11 +44,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRequest, Ctx>> {
let db = &*state.store;
let merchant_id = &merchant_account.merchant_id;
let storage_scheme = merchant_account.storage_scheme;
@ -202,50 +198,71 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
// The operation merges mandate data from both request and payment_attempt
let setup_mandate = setup_mandate.map(Into::into);
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id: None,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id: None,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(CustomerDetails {
customer_id: request.customer_id.clone(),
name: request.name.clone(),
email: request.email.clone(),
phone: request.phone.clone(),
phone_country_code: request.phone_country_code.clone(),
}),
))
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
};
let customer_details = Some(CustomerDetails {
customer_id: request.customer_id.clone(),
name: request.name.clone(),
email: request.email.clone(),
phone: request.phone.clone(),
phone_country_code: request.phone_country_code.clone(),
});
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details,
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -50,11 +50,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRequest, Ctx>> {
let db = &*state.store;
let merchant_id = &merchant_account.merchant_id;
let storage_scheme = merchant_account.storage_scheme;
@ -65,7 +61,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
.change_context(errors::ApiErrorResponse::PaymentNotFound)?;
// Stage 1
let store = state.clone().store;
let m_merchant_id = merchant_id.clone();
let payment_intent_fut = tokio::spawn(
@ -137,8 +132,29 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
let customer_details = helpers::get_customer_details_from_request(request);
// Stage 2
let attempt_id = payment_intent.active_attempt.get_id();
let profile_id = payment_intent
.profile_id
.clone()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let store = state.store.clone();
let business_profile_fut = tokio::spawn(async move {
store
.find_business_profile_by_profile_id(&profile_id)
.map(|business_profile_result| {
business_profile_result.to_not_found_response(
errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
},
)
})
.await
});
let store = state.clone().store;
let m_payment_id = payment_intent.payment_id.clone();
let m_merchant_id = merchant_id.clone();
@ -235,48 +251,72 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
.in_current_span(),
);
let (mut payment_attempt, shipping_address, billing_address) = match payment_intent.status {
api_models::enums::IntentStatus::RequiresCustomerAction
| api_models::enums::IntentStatus::RequiresMerchantAction
| api_models::enums::IntentStatus::RequiresPaymentMethod
| api_models::enums::IntentStatus::RequiresConfirmation => {
let (payment_attempt, shipping_address, billing_address, _) = tokio::try_join!(
utils::flatten_join_error(payment_attempt_fut),
utils::flatten_join_error(shipping_address_fut),
utils::flatten_join_error(billing_address_fut),
utils::flatten_join_error(config_update_fut)
)?;
// Based on whether a retry can be performed or not, fetch relevant entities
let (mut payment_attempt, shipping_address, billing_address, business_profile) =
match payment_intent.status {
api_models::enums::IntentStatus::RequiresCustomerAction
| api_models::enums::IntentStatus::RequiresMerchantAction
| api_models::enums::IntentStatus::RequiresPaymentMethod
| api_models::enums::IntentStatus::RequiresConfirmation => {
// Normal payment
let (payment_attempt, shipping_address, billing_address, business_profile, _) =
tokio::try_join!(
utils::flatten_join_error(payment_attempt_fut),
utils::flatten_join_error(shipping_address_fut),
utils::flatten_join_error(billing_address_fut),
utils::flatten_join_error(business_profile_fut),
utils::flatten_join_error(config_update_fut)
)?;
(payment_attempt, shipping_address, billing_address)
}
_ => {
let (mut payment_attempt, shipping_address, billing_address, _) = tokio::try_join!(
utils::flatten_join_error(payment_attempt_fut),
utils::flatten_join_error(shipping_address_fut),
utils::flatten_join_error(billing_address_fut),
utils::flatten_join_error(config_update_fut)
)?;
let attempt_type = helpers::get_attempt_type(
&payment_intent,
&payment_attempt,
request,
"confirm",
)?;
(payment_intent, payment_attempt) = attempt_type
.modify_payment_intent_and_payment_attempt(
request,
payment_intent,
(
payment_attempt,
&*state.store,
storage_scheme,
shipping_address,
billing_address,
business_profile,
)
.await?;
}
_ => {
// Retry payment
let (
mut payment_attempt,
shipping_address,
billing_address,
business_profile,
_,
) = tokio::try_join!(
utils::flatten_join_error(payment_attempt_fut),
utils::flatten_join_error(shipping_address_fut),
utils::flatten_join_error(billing_address_fut),
utils::flatten_join_error(business_profile_fut),
utils::flatten_join_error(config_update_fut)
)?;
(payment_attempt, shipping_address, billing_address)
}
};
let attempt_type = helpers::get_attempt_type(
&payment_intent,
&payment_attempt,
request,
"confirm",
)?;
// 3
(payment_intent, payment_attempt) = attempt_type
.modify_payment_intent_and_payment_attempt(
request,
payment_intent,
payment_attempt,
&*state.store,
storage_scheme,
)
.await?;
(
payment_attempt,
shipping_address,
billing_address,
business_profile,
)
}
};
payment_intent.order_details = request
.get_order_details_as_value()
@ -382,6 +422,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
sm.mandate_type = payment_attempt.mandate_details.clone().or(sm.mandate_type);
sm
});
Self::validate_request_surcharge_details_with_session_surcharge_details(
state,
&payment_attempt,
@ -394,44 +435,49 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
&payment_attempt,
);
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id: None,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details,
frm_message: None,
payment_link_data: None,
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id: None,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(customer_details),
))
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details,
frm_message: None,
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details: Some(customer_details),
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -53,11 +53,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
merchant_key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRequest, Ctx>> {
let db = &*state.store;
let ephemeral_key = Self::get_ephemeral_key(request, state, merchant_account).await;
let merchant_id = &merchant_account.merchant_id;
@ -196,6 +192,20 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
payment_id: payment_id.clone(),
})?;
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let mandate_id = request
.mandate_id
.as_ref()
@ -246,6 +256,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
request.confirm,
self,
);
let creds_identifier = request
.merchant_connector_details
.as_ref()
@ -265,9 +276,8 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
.transpose()?;
// The operation merges mandate data from both request and payment_attempt
let setup_mandate: Option<MandateData> = setup_mandate.map(Into::into);
let setup_mandate = setup_mandate.map(MandateData::from);
// populate payment_data.surcharge_details from request
let surcharge_details = request.surcharge_details.map(|surcharge_details| {
payment_methods::SurchargeDetailsResponse {
surcharge: payment_methods::Surcharge::Fixed(surcharge_details.surcharge_amount),
@ -280,44 +290,49 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
}
});
Ok((
operation,
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
refunds: vec![],
disputes: vec![],
attempts: None,
force_sync: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key,
multiple_capture_data: None,
redirect_response: None,
surcharge_details,
frm_message: None,
payment_link_data,
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id,
mandate_connector,
setup_mandate,
token,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(customer_details),
))
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
refunds: vec![],
disputes: vec![],
attempts: None,
force_sync: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key,
multiple_capture_data: None,
redirect_response: None,
surcharge_details,
frm_message: None,
payment_link_data,
};
let get_trackers_response = operations::GetTrackerResponse {
operation,
customer_details: Some(customer_details),
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -11,7 +11,7 @@ use crate::{
core::{
errors::{self, RouterResult, StorageErrorExt},
payment_methods::PaymentMethodRetrieve,
payments::{helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
payments::{helpers, operations, PaymentAddress, PaymentData},
},
routes::AppState,
services,
@ -41,11 +41,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, PaymentsRejectRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, PaymentsRejectRequest, Ctx>> {
let db = &*state.store;
let merchant_id = &merchant_account.merchant_id;
let storage_scheme = merchant_account.storage_scheme;
@ -114,45 +110,64 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
format!("Error while retrieving frm_response, merchant_id: {}, payment_id: {attempt_id}", &merchant_account.merchant_id)
});
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: None,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: None,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
sessions_token: vec![],
card_cvc: None,
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: frm_response.ok(),
payment_link_data: None,
let business_profile = state
.store
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: None,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
None,
))
confirm: None,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: frm_response.ok(),
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details: None,
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -43,11 +43,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsSessionRequest, Ctx>,
PaymentData<F>,
Option<payments::CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsSessionRequest, Ctx>> {
let payment_id = payment_id
.get_payment_intent_id()
.change_context(errors::ApiErrorResponse::PaymentNotFound)?;
@ -152,44 +148,63 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
.await
.transpose()?;
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
token: None,
setup_mandate: None,
address: payments::PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: None,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
token: None,
setup_mandate: None,
address: payments::PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(customer_details),
))
confirm: None,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details: Some(customer_details),
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -42,11 +42,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
mechant_key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsStartRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsStartRequest, Ctx>> {
let (mut payment_intent, payment_attempt, currency, amount);
let db = &*state.store;
@ -126,44 +122,63 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
..CustomerDetails::default()
};
Ok((
Box::new(self),
PaymentData {
flow: PhantomData,
payment_intent,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: payment_attempt.payment_token.clone(),
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: Some(payment_attempt.confirm),
payment_attempt,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
currency,
amount,
email: None,
mandate_id: None,
mandate_connector: None,
setup_mandate: None,
token: payment_attempt.payment_token.clone(),
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(customer_details),
))
confirm: Some(payment_attempt.confirm),
payment_attempt,
payment_method_data: None,
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: None,
creds_identifier: None,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
frm_message: None,
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(self),
customer_details: Some(customer_details),
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}

View File

@ -190,11 +190,8 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRetrieveRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRetrieveRequest, Ctx>>
{
get_tracker_for_sync(
payment_id,
merchant_account,
@ -221,12 +218,8 @@ async fn get_tracker_for_sync<
request: &api::PaymentsRetrieveRequest,
operation: Op,
storage_scheme: enums::MerchantStorageScheme,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRetrieveRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
let (payment_intent, mut payment_attempt, currency, amount);
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRetrieveRequest, Ctx>> {
let (payment_intent, payment_attempt, currency, amount);
(payment_intent, payment_attempt) = get_payment_intent_payment_attempt(
db,
@ -250,7 +243,6 @@ async fn get_tracker_for_sync<
let payment_id_str = payment_attempt.payment_id.clone();
payment_attempt.encoded_data = request.param.clone();
currency = payment_attempt.currency.get_required_value("currency")?;
amount = payment_attempt.amount.into();
@ -357,53 +349,74 @@ async fn get_tracker_for_sync<
})
.await
.transpose()?;
Ok((
Box::new(operation),
PaymentData {
flow: PhantomData,
payment_intent,
currency,
amount,
email: None,
mandate_id: payment_attempt.mandate_id.clone().map(|id| {
api_models::payments::MandateIds {
mandate_id: id,
mandate_reference_id: None,
}
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
currency,
amount,
email: None,
mandate_id: payment_attempt
.mandate_id
.clone()
.map(|id| api_models::payments::MandateIds {
mandate_id: id,
mandate_reference_id: None,
}),
mandate_connector: None,
setup_mandate: None,
token: None,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: Some(request.force_sync),
payment_method_data: None,
force_sync: Some(
request.force_sync
&& (helpers::check_force_psync_precondition(&payment_attempt.status)
|| contains_encoded_data),
),
payment_attempt,
refunds,
disputes,
attempts,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data,
redirect_response: None,
payment_link_data: None,
surcharge_details: None,
frm_message: frm_response.ok(),
mandate_connector: None,
setup_mandate: None,
token: None,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
None,
))
confirm: Some(request.force_sync),
payment_method_data: None,
force_sync: Some(
request.force_sync
&& (helpers::check_force_psync_precondition(&payment_attempt.status)
|| contains_encoded_data),
),
payment_attempt,
refunds,
disputes,
attempts,
sessions_token: vec![],
card_cvc: None,
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data: None,
ephemeral_key: None,
multiple_capture_data,
redirect_response: None,
payment_link_data: None,
surcharge_details: None,
frm_message: frm_response.ok(),
};
let get_trackers_response = operations::GetTrackerResponse {
operation: Box::new(operation),
customer_details: None,
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>

View File

@ -44,11 +44,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
auth_flow: services::AuthFlow,
) -> RouterResult<(
BoxedOperation<'a, F, api::PaymentsRequest, Ctx>,
PaymentData<F>,
Option<CustomerDetails>,
)> {
) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRequest, Ctx>> {
let (mut payment_intent, mut payment_attempt, currency): (_, _, storage_enums::Currency);
let payment_id = payment_id
@ -304,48 +300,67 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
// The operation merges mandate data from both request and payment_attempt
let setup_mandate = setup_mandate.map(Into::into);
let profile_id = payment_intent
.profile_id
.as_ref()
.get_required_value("profile_id")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("'profile_id' not set in payment intent")?;
let business_profile = db
.find_business_profile_by_profile_id(profile_id)
.await
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
id: profile_id.to_string(),
})?;
let surcharge_details = request.surcharge_details.map(|request_surcharge_details| {
request_surcharge_details.get_surcharge_details_object(payment_attempt.amount)
});
Ok((
next_operation,
PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id,
mandate_connector,
token,
setup_mandate,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details,
frm_message: None,
payment_link_data: None,
let payment_data = PaymentData {
flow: PhantomData,
payment_intent,
payment_attempt,
currency,
amount,
email: request.email.clone(),
mandate_id,
mandate_connector,
token,
setup_mandate,
address: PaymentAddress {
shipping: shipping_address.as_ref().map(|a| a.into()),
billing: billing_address.as_ref().map(|a| a.into()),
},
Some(customer_details),
))
confirm: request.confirm,
payment_method_data: request.payment_method_data.clone(),
force_sync: None,
refunds: vec![],
disputes: vec![],
attempts: None,
sessions_token: vec![],
card_cvc: request.card_cvc.clone(),
creds_identifier,
pm_token: None,
connector_customer_id: None,
recurring_mandate_payment_data,
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details,
frm_message: None,
payment_link_data: None,
};
let get_trackers_response = operations::GetTrackerResponse {
operation: next_operation,
customer_details: Some(customer_details),
payment_data,
business_profile,
};
Ok(get_trackers_response)
}
}