mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 12:06:56 +08:00
fix: handle session and confirm flow discrepancy in surcharge details (#2696)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@ -1052,6 +1052,8 @@ pub async fn list_payment_methods(
|
||||
amount_capturable: None,
|
||||
updated_by: merchant_account.storage_scheme.to_string(),
|
||||
merchant_connector_id: None,
|
||||
surcharge_amount: None,
|
||||
tax_amount: None,
|
||||
};
|
||||
|
||||
state
|
||||
|
||||
@ -14,7 +14,7 @@ use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant, vec::IntoI
|
||||
|
||||
use api_models::{
|
||||
enums,
|
||||
payment_methods::{SurchargeDetailsResponse, SurchargeMetadata},
|
||||
payment_methods::{Surcharge, SurchargeDetailsResponse},
|
||||
payments::HeaderPayload,
|
||||
};
|
||||
use common_utils::{ext_traits::AsyncExt, pii};
|
||||
@ -290,6 +290,8 @@ where
|
||||
}
|
||||
|
||||
api::ConnectorCallType::SessionMultiple(connectors) => {
|
||||
let session_surcharge_data =
|
||||
get_session_surcharge_data(&payment_data.payment_attempt);
|
||||
call_multiple_connectors_service(
|
||||
state,
|
||||
&merchant_account,
|
||||
@ -298,7 +300,7 @@ where
|
||||
&operation,
|
||||
payment_data,
|
||||
&customer,
|
||||
None,
|
||||
session_surcharge_data,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
@ -353,6 +355,21 @@ pub fn get_connector_data(
|
||||
.attach_printable("Connector not found in connectors iterator")
|
||||
}
|
||||
|
||||
pub fn get_session_surcharge_data(
|
||||
payment_attempt: &data_models::payments::payment_attempt::PaymentAttempt,
|
||||
) -> Option<api::SessionSurchargeDetails> {
|
||||
payment_attempt.surcharge_amount.map(|surcharge_amount| {
|
||||
let tax_on_surcharge_amount = payment_attempt.tax_amount.unwrap_or(0);
|
||||
let final_amount = payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount;
|
||||
api::SessionSurchargeDetails::PreDetermined(SurchargeDetailsResponse {
|
||||
surcharge: Surcharge::Fixed(surcharge_amount),
|
||||
tax_on_surcharge: None,
|
||||
surcharge_amount,
|
||||
tax_on_surcharge_amount,
|
||||
final_amount,
|
||||
})
|
||||
})
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn payments_core<F, Res, Req, Op, FData, Ctx>(
|
||||
state: AppState,
|
||||
@ -920,7 +937,7 @@ pub async fn call_multiple_connectors_service<F, Op, Req, Ctx>(
|
||||
_operation: &Op,
|
||||
mut payment_data: PaymentData<F>,
|
||||
customer: &Option<domain::Customer>,
|
||||
session_surcharge_metadata: Option<SurchargeMetadata>,
|
||||
session_surcharge_details: Option<api::SessionSurchargeDetails>,
|
||||
) -> RouterResult<PaymentData<F>>
|
||||
where
|
||||
Op: Debug,
|
||||
@ -957,18 +974,16 @@ where
|
||||
)
|
||||
.await?;
|
||||
|
||||
payment_data.surcharge_details = session_surcharge_metadata
|
||||
.as_ref()
|
||||
.and_then(|surcharge_metadata| {
|
||||
surcharge_metadata.surcharge_results.get(
|
||||
&SurchargeMetadata::get_key_for_surcharge_details_hash_map(
|
||||
payment_data.surcharge_details =
|
||||
session_surcharge_details
|
||||
.as_ref()
|
||||
.and_then(|session_surcharge_details| {
|
||||
session_surcharge_details.fetch_surcharge_details(
|
||||
&session_connector_data.payment_method_type.into(),
|
||||
&session_connector_data.payment_method_type,
|
||||
None,
|
||||
),
|
||||
)
|
||||
})
|
||||
.cloned();
|
||||
)
|
||||
});
|
||||
|
||||
let router_data = payment_data
|
||||
.construct_router_data(
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use api_models::{enums::FrmSuggestion, payment_methods};
|
||||
use api_models::{
|
||||
enums::FrmSuggestion,
|
||||
payment_methods::{self, SurchargeDetailsResponse},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use common_utils::ext_traits::{AsyncExt, Encode};
|
||||
use error_stack::ResultExt;
|
||||
use futures::FutureExt;
|
||||
use redis_interface::errors::RedisError;
|
||||
use router_derive::PaymentOperation;
|
||||
use router_env::{instrument, tracing};
|
||||
|
||||
@ -14,6 +18,7 @@ use crate::{
|
||||
errors::{self, CustomResult, RouterResult, StorageErrorExt},
|
||||
payment_methods::PaymentMethodRetrieve,
|
||||
payments::{self, helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
|
||||
utils::get_individual_surcharge_detail_from_redis,
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
@ -305,19 +310,17 @@ 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,
|
||||
request,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// 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),
|
||||
tax_on_surcharge: None,
|
||||
surcharge_amount: surcharge_details.surcharge_amount,
|
||||
tax_on_surcharge_amount: surcharge_details.tax_amount.unwrap_or(0),
|
||||
final_amount: payment_attempt.amount
|
||||
+ surcharge_details.surcharge_amount
|
||||
+ surcharge_details.tax_amount.unwrap_or(0),
|
||||
}
|
||||
});
|
||||
let surcharge_details = Self::get_surcharge_details_from_payment_request_or_payment_attempt(
|
||||
request,
|
||||
&payment_attempt,
|
||||
);
|
||||
|
||||
Ok((
|
||||
Box::new(self),
|
||||
@ -529,14 +532,6 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
|
||||
.take();
|
||||
let order_details = payment_data.payment_intent.order_details.clone();
|
||||
let metadata = payment_data.payment_intent.metadata.clone();
|
||||
let surcharge_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.surcharge_amount);
|
||||
let tax_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.tax_on_surcharge_amount);
|
||||
let authorized_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
@ -562,8 +557,6 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
|
||||
error_code,
|
||||
error_message,
|
||||
amount_capturable: Some(authorized_amount),
|
||||
surcharge_amount,
|
||||
tax_amount,
|
||||
updated_by: storage_scheme.to_string(),
|
||||
merchant_connector_id,
|
||||
},
|
||||
@ -672,3 +665,92 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl PaymentConfirm {
|
||||
pub async fn validate_request_surcharge_details_with_session_surcharge_details(
|
||||
state: &AppState,
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
request: &api::PaymentsRequest,
|
||||
) -> RouterResult<()> {
|
||||
match (
|
||||
request.surcharge_details,
|
||||
request.payment_method_data.as_ref(),
|
||||
) {
|
||||
(Some(request_surcharge_details), Some(payment_method_data)) => {
|
||||
if let Some(payment_method_type) =
|
||||
payment_method_data.get_payment_method_type_if_session_token_type()
|
||||
{
|
||||
let invalid_surcharge_details_error = Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "surcharge_details sent in session token flow doesn't match with the one sent in confirm request".into(),
|
||||
}.into());
|
||||
if let Some(attempt_surcharge_amount) = payment_attempt.surcharge_amount {
|
||||
// payment_attempt.surcharge_amount will be Some if some surcharge was sent in payment create
|
||||
// if surcharge was sent in payment create call, the same would have been sent to the connector during session call
|
||||
// So verify the same
|
||||
if request_surcharge_details.surcharge_amount != attempt_surcharge_amount
|
||||
|| request_surcharge_details.tax_amount != payment_attempt.tax_amount
|
||||
{
|
||||
return invalid_surcharge_details_error;
|
||||
}
|
||||
} else {
|
||||
// if not sent in payment create
|
||||
// verify that any calculated surcharge sent in session flow is same as the one sent in confirm
|
||||
return match get_individual_surcharge_detail_from_redis(
|
||||
state,
|
||||
&payment_method_type.into(),
|
||||
&payment_method_type,
|
||||
None,
|
||||
&payment_attempt.attempt_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(surcharge_details) => utils::when(
|
||||
!surcharge_details
|
||||
.is_request_surcharge_matching(request_surcharge_details),
|
||||
|| invalid_surcharge_details_error,
|
||||
),
|
||||
Err(err) if err.current_context() == &RedisError::NotFound => {
|
||||
utils::when(!request_surcharge_details.is_surcharge_zero(), || {
|
||||
invalid_surcharge_details_error
|
||||
})
|
||||
}
|
||||
Err(err) => Err(err)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to fetch redis value"),
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
(Some(_request_surcharge_details), None) => {
|
||||
Err(errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "payment_method_data",
|
||||
}
|
||||
.into())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_surcharge_details_from_payment_request_or_payment_attempt(
|
||||
payment_request: &api::PaymentsRequest,
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
) -> Option<SurchargeDetailsResponse> {
|
||||
payment_request
|
||||
.surcharge_details
|
||||
.map(|surcharge_details| {
|
||||
surcharge_details.get_surcharge_details_object(payment_attempt.amount)
|
||||
}) // if not passed in confirm request, look inside payment_attempt
|
||||
.or(payment_attempt
|
||||
.surcharge_amount
|
||||
.map(|surcharge_amount| SurchargeDetailsResponse {
|
||||
surcharge: payment_methods::Surcharge::Fixed(surcharge_amount),
|
||||
tax_on_surcharge: None,
|
||||
surcharge_amount,
|
||||
tax_on_surcharge_amount: payment_attempt.tax_amount.unwrap_or(0),
|
||||
final_amount: payment_attempt.amount
|
||||
+ surcharge_amount
|
||||
+ payment_attempt.tax_amount.unwrap_or(0),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use api_models::enums::FrmSuggestion;
|
||||
use api_models::{enums::FrmSuggestion, payment_methods};
|
||||
use async_trait::async_trait;
|
||||
use common_utils::ext_traits::{AsyncExt, Encode, ValueExt};
|
||||
use data_models::{mandates::MandateData, payments::payment_attempt::PaymentAttempt};
|
||||
@ -267,6 +267,19 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
|
||||
// The operation merges mandate data from both request and payment_attempt
|
||||
let setup_mandate: Option<MandateData> = setup_mandate.map(Into::into);
|
||||
|
||||
// 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),
|
||||
tax_on_surcharge: None,
|
||||
surcharge_amount: surcharge_details.surcharge_amount,
|
||||
tax_on_surcharge_amount: surcharge_details.tax_amount.unwrap_or(0),
|
||||
final_amount: payment_attempt.amount
|
||||
+ surcharge_details.surcharge_amount
|
||||
+ surcharge_details.tax_amount.unwrap_or(0),
|
||||
}
|
||||
});
|
||||
|
||||
Ok((
|
||||
operation,
|
||||
PaymentData {
|
||||
@ -299,7 +312,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
|
||||
ephemeral_key,
|
||||
multiple_capture_data: None,
|
||||
redirect_response: None,
|
||||
surcharge_details: None,
|
||||
surcharge_details,
|
||||
frm_message: None,
|
||||
payment_link_data,
|
||||
},
|
||||
@ -421,6 +434,15 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
|
||||
let authorized_amount = payment_data.payment_attempt.amount;
|
||||
let merchant_connector_id = payment_data.payment_attempt.merchant_connector_id.clone();
|
||||
|
||||
let surcharge_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.surcharge_amount);
|
||||
let tax_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.tax_on_surcharge_amount);
|
||||
|
||||
payment_data.payment_attempt = db
|
||||
.update_payment_attempt_with_attempt_id(
|
||||
payment_data.payment_attempt,
|
||||
@ -432,6 +454,8 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
|
||||
true => Some(authorized_amount),
|
||||
false => None,
|
||||
},
|
||||
surcharge_amount,
|
||||
tax_amount,
|
||||
updated_by: storage_scheme.to_string(),
|
||||
merchant_connector_id,
|
||||
},
|
||||
|
||||
@ -466,6 +466,8 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
|
||||
} else {
|
||||
None
|
||||
},
|
||||
surcharge_amount: router_data.request.get_surcharge_amount(),
|
||||
tax_amount: router_data.request.get_tax_on_surcharge_amount(),
|
||||
updated_by: storage_scheme.to_string(),
|
||||
authentication_data,
|
||||
encoded_data,
|
||||
|
||||
@ -304,6 +304,10 @@ 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 surcharge_details = request.surcharge_details.map(|request_surcharge_details| {
|
||||
request_surcharge_details.get_surcharge_details_object(payment_attempt.amount)
|
||||
});
|
||||
|
||||
Ok((
|
||||
next_operation,
|
||||
PaymentData {
|
||||
@ -336,7 +340,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
|
||||
ephemeral_key: None,
|
||||
multiple_capture_data: None,
|
||||
redirect_response: None,
|
||||
surcharge_details: None,
|
||||
surcharge_details,
|
||||
frm_message: None,
|
||||
payment_link_data: None,
|
||||
},
|
||||
@ -467,6 +471,14 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
|
||||
let payment_experience = payment_data.payment_attempt.payment_experience;
|
||||
let amount_to_capture = payment_data.payment_attempt.amount_to_capture;
|
||||
let capture_method = payment_data.payment_attempt.capture_method;
|
||||
let surcharge_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.surcharge_amount);
|
||||
let tax_amount = payment_data
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.tax_on_surcharge_amount);
|
||||
payment_data.payment_attempt = db
|
||||
.update_payment_attempt_with_attempt_id(
|
||||
payment_data.payment_attempt,
|
||||
@ -483,6 +495,8 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
|
||||
business_sub_label,
|
||||
amount_to_capture,
|
||||
capture_method,
|
||||
surcharge_amount,
|
||||
tax_amount,
|
||||
updated_by: storage_scheme.to_string(),
|
||||
},
|
||||
storage_scheme,
|
||||
|
||||
@ -412,6 +412,8 @@ where
|
||||
} else {
|
||||
None
|
||||
},
|
||||
surcharge_amount: None,
|
||||
tax_amount: None,
|
||||
updated_by: storage_scheme.to_string(),
|
||||
authentication_data,
|
||||
encoded_data,
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
use std::{marker::PhantomData, str::FromStr};
|
||||
|
||||
use api_models::enums::{DisputeStage, DisputeStatus};
|
||||
use api_models::{
|
||||
enums::{DisputeStage, DisputeStatus},
|
||||
payment_methods::{SurchargeDetailsResponse, SurchargeMetadata},
|
||||
};
|
||||
#[cfg(feature = "payouts")]
|
||||
use common_utils::{crypto::Encryptable, pii::Email};
|
||||
use common_utils::{errors::CustomResult, ext_traits::AsyncExt};
|
||||
use common_utils::{
|
||||
errors::CustomResult,
|
||||
ext_traits::{AsyncExt, Encode},
|
||||
};
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
use euclid::enums as euclid_enums;
|
||||
use redis_interface::errors::RedisError;
|
||||
use router_env::{instrument, tracing};
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -1073,3 +1081,65 @@ pub fn get_flow_name<F>() -> RouterResult<String> {
|
||||
.attach_printable("Flow stringify failed")?
|
||||
.to_string())
|
||||
}
|
||||
|
||||
pub async fn persist_individual_surcharge_details_in_redis(
|
||||
state: &AppState,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
surcharge_metadata: &SurchargeMetadata,
|
||||
) -> RouterResult<()> {
|
||||
if !surcharge_metadata.is_empty_result() {
|
||||
let redis_conn = state
|
||||
.store
|
||||
.get_redis_conn()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to get redis connection")?;
|
||||
let redis_key = SurchargeMetadata::get_surcharge_metadata_redis_key(
|
||||
&surcharge_metadata.payment_attempt_id,
|
||||
);
|
||||
|
||||
let mut value_list = Vec::with_capacity(surcharge_metadata.get_surcharge_results_size());
|
||||
for (key, value) in surcharge_metadata
|
||||
.get_individual_surcharge_key_value_pairs()
|
||||
.into_iter()
|
||||
{
|
||||
value_list.push((
|
||||
key,
|
||||
Encode::<SurchargeDetailsResponse>::encode_to_string_of_json(&value)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to encode to string of json")?,
|
||||
));
|
||||
}
|
||||
let intent_fulfillment_time = merchant_account
|
||||
.intent_fulfillment_time
|
||||
.unwrap_or(consts::DEFAULT_FULFILLMENT_TIME);
|
||||
redis_conn
|
||||
.set_hash_fields(&redis_key, value_list, Some(intent_fulfillment_time))
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to write to redis")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_individual_surcharge_detail_from_redis(
|
||||
state: &AppState,
|
||||
payment_method: &euclid_enums::PaymentMethod,
|
||||
payment_method_type: &euclid_enums::PaymentMethodType,
|
||||
card_network: Option<euclid_enums::CardNetwork>,
|
||||
payment_attempt_id: &str,
|
||||
) -> CustomResult<SurchargeDetailsResponse, RedisError> {
|
||||
let redis_conn = state
|
||||
.store
|
||||
.get_redis_conn()
|
||||
.attach_printable("Failed to get redis connection")?;
|
||||
let redis_key = SurchargeMetadata::get_surcharge_metadata_redis_key(payment_attempt_id);
|
||||
let value_key = SurchargeMetadata::get_surcharge_details_redis_hashset_key(
|
||||
payment_method,
|
||||
payment_method_type,
|
||||
card_network.as_ref(),
|
||||
);
|
||||
|
||||
redis_conn
|
||||
.get_hash_field_and_deserialize(&redis_key, &value_key, "SurchargeDetailsResponse")
|
||||
.await
|
||||
}
|
||||
|
||||
@ -98,11 +98,7 @@ pub trait ConnectorValidation: ConnectorCommon {
|
||||
}
|
||||
|
||||
fn validate_if_surcharge_implemented(&self) -> CustomResult<(), errors::ConnectorError> {
|
||||
Err(errors::ConnectorError::NotImplemented(format!(
|
||||
"Surcharge not implemented for {}",
|
||||
self.id()
|
||||
))
|
||||
.into())
|
||||
Err(errors::ConnectorError::NotImplemented(format!("Surcharge for {}", self.id())).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -547,11 +547,31 @@ pub trait Capturable {
|
||||
fn get_capture_amount(&self) -> Option<i64> {
|
||||
Some(0)
|
||||
}
|
||||
fn get_surcharge_amount(&self) -> Option<i64> {
|
||||
None
|
||||
}
|
||||
fn get_tax_on_surcharge_amount(&self) -> Option<i64> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Capturable for PaymentsAuthorizeData {
|
||||
fn get_capture_amount(&self) -> Option<i64> {
|
||||
Some(self.amount)
|
||||
let final_amount = self
|
||||
.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.final_amount);
|
||||
final_amount.or(Some(self.amount))
|
||||
}
|
||||
fn get_surcharge_amount(&self) -> Option<i64> {
|
||||
self.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.surcharge_amount)
|
||||
}
|
||||
fn get_tax_on_surcharge_amount(&self) -> Option<i64> {
|
||||
self.surcharge_details
|
||||
.as_ref()
|
||||
.map(|surcharge_details| surcharge_details.tax_on_surcharge_amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ pub mod webhooks;
|
||||
|
||||
use std::{fmt::Debug, str::FromStr};
|
||||
|
||||
use api_models::payment_methods::{SurchargeDetailsResponse, SurchargeMetadata};
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
|
||||
pub use self::{
|
||||
@ -214,6 +215,30 @@ pub struct SessionConnectorData {
|
||||
pub business_sub_label: Option<String>,
|
||||
}
|
||||
|
||||
/// Session Surcharge type
|
||||
pub enum SessionSurchargeDetails {
|
||||
/// Surcharge is calculated by hyperswitch
|
||||
Calculated(SurchargeMetadata),
|
||||
/// Surcharge is sent by merchant
|
||||
PreDetermined(SurchargeDetailsResponse),
|
||||
}
|
||||
|
||||
impl SessionSurchargeDetails {
|
||||
pub fn fetch_surcharge_details(
|
||||
&self,
|
||||
payment_method: &enums::PaymentMethod,
|
||||
payment_method_type: &enums::PaymentMethodType,
|
||||
card_network: Option<&enums::CardNetwork>,
|
||||
) -> Option<SurchargeDetailsResponse> {
|
||||
match self {
|
||||
Self::Calculated(surcharge_metadata) => surcharge_metadata
|
||||
.get_surcharge_details(payment_method, payment_method_type, card_network)
|
||||
.cloned(),
|
||||
Self::PreDetermined(surcharge_details) => Some(surcharge_details.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ConnectorChoice {
|
||||
SessionMultiple(Vec<SessionConnectorData>),
|
||||
StraightThrough(serde_json::Value),
|
||||
|
||||
Reference in New Issue
Block a user