mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 09:38:33 +08:00
feat(compatibility): add mandates support in stripe compatibility (#897)
Co-authored-by: Sahkal Poddar <sahkal.poddar@juspay.in> Co-authored-by: Sarthak Soni <sarthak.soni@juspay.in> Co-authored-by: Sarthak Soni <76486416+Sarthak1799@users.noreply.github.com> Co-authored-by: Abhishek Marrivagu <abhi.codes10@gmail.com>
This commit is contained in:
@ -47,6 +47,7 @@ locker_decryption_key1 = ""
|
||||
locker_decryption_key2 = ""
|
||||
vault_encryption_key = ""
|
||||
vault_private_key = ""
|
||||
tunnel_private_key = ""
|
||||
|
||||
[connectors.supported]
|
||||
wallets = ["klarna", "braintree", "applepay"]
|
||||
|
||||
@ -147,17 +147,17 @@ where
|
||||
///
|
||||
/// Extending functionalities of `bytes::Bytes`
|
||||
///
|
||||
pub trait BytesExt<T> {
|
||||
pub trait BytesExt {
|
||||
///
|
||||
/// Convert `bytes::Bytes` into type `<T>` using `serde::Deserialize`
|
||||
///
|
||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
fn parse_struct<'de, T>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>;
|
||||
}
|
||||
|
||||
impl<T> BytesExt<T> for bytes::Bytes {
|
||||
fn parse_struct<'de>(&'de self, _type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
impl BytesExt for bytes::Bytes {
|
||||
fn parse_struct<'de, T>(&'de self, _type_name: &str) -> CustomResult<T, errors::ParsingError>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
|
||||
@ -20,6 +20,7 @@ impl StripeApis {
|
||||
.service(app::PaymentIntents::server(state.clone()))
|
||||
.service(app::Refunds::server(state.clone()))
|
||||
.service(app::Customers::server(state.clone()))
|
||||
.service(app::Webhooks::server(state))
|
||||
.service(app::Webhooks::server(state.clone()))
|
||||
.service(app::Mandates::server(state))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use actix_web::{web, Scope};
|
||||
|
||||
use super::{customers::*, payment_intents::*, refunds::*, setup_intents::*, webhooks::*};
|
||||
use crate::routes::{self, webhooks};
|
||||
use crate::routes::{self, mandates, webhooks};
|
||||
|
||||
pub struct PaymentIntents;
|
||||
|
||||
@ -111,3 +111,13 @@ impl Webhooks {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mandates;
|
||||
|
||||
impl Mandates {
|
||||
pub fn server(config: routes::AppState) -> Scope {
|
||||
web::scope("/payment_methods")
|
||||
.app_data(web::Data::new(config))
|
||||
.service(web::resource("/{id}/detach").route(web::post().to(mandates::revoke_mandate)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use api_models::payments;
|
||||
use common_utils::{date_time, ext_traits::StringExt, pii as secret};
|
||||
use error_stack::ResultExt;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@ -10,7 +10,7 @@ use crate::{
|
||||
pii::{self, Email, PeekInterface},
|
||||
types::{
|
||||
api::{admin, enums as api_enums},
|
||||
transformers::{ForeignFrom, ForeignInto},
|
||||
transformers::{ForeignFrom, ForeignTryFrom},
|
||||
},
|
||||
};
|
||||
|
||||
@ -59,6 +59,7 @@ impl From<StripePaymentMethodType> for api_enums::PaymentMethod {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Deserialize, Clone)]
|
||||
pub struct StripePaymentMethodData {
|
||||
#[serde(rename = "type")]
|
||||
@ -143,12 +144,32 @@ pub struct StripePaymentIntentRequest {
|
||||
pub client_secret: Option<pii::Secret<String>>,
|
||||
pub payment_method_options: Option<StripePaymentMethodOptions>,
|
||||
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
|
||||
pub mandate_id: Option<String>,
|
||||
pub off_session: Option<bool>,
|
||||
}
|
||||
|
||||
impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
|
||||
type Error = error_stack::Report<errors::ApiErrorResponse>;
|
||||
fn try_from(item: StripePaymentIntentRequest) -> errors::RouterResult<Self> {
|
||||
Ok(Self {
|
||||
let (mandate_options, authentication_type) = match item.payment_method_options {
|
||||
Some(pmo) => {
|
||||
let StripePaymentMethodOptions::Card {
|
||||
request_three_d_secure,
|
||||
mandate_options,
|
||||
}: StripePaymentMethodOptions = pmo;
|
||||
(
|
||||
Option::<payments::MandateData>::foreign_try_from((
|
||||
mandate_options,
|
||||
item.currency.to_owned(),
|
||||
))?,
|
||||
Some(api_enums::AuthenticationType::foreign_from(
|
||||
request_three_d_secure,
|
||||
)),
|
||||
)
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
let request = Ok(Self {
|
||||
payment_id: item.id.map(payments::PaymentIdType::PaymentIntentId),
|
||||
amount: item.amount.map(|amount| amount.into()),
|
||||
connector: item.connector,
|
||||
@ -188,16 +209,15 @@ impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
|
||||
statement_descriptor_suffix: item.statement_descriptor_suffix,
|
||||
metadata: item.metadata,
|
||||
client_secret: item.client_secret.map(|s| s.peek().clone()),
|
||||
authentication_type: item.payment_method_options.map(|pmo| {
|
||||
let StripePaymentMethodOptions::Card {
|
||||
request_three_d_secure,
|
||||
} = pmo;
|
||||
|
||||
request_three_d_secure.foreign_into()
|
||||
}),
|
||||
authentication_type,
|
||||
mandate_data: mandate_options,
|
||||
merchant_connector_details: item.merchant_connector_details,
|
||||
setup_future_usage: item.setup_future_usage,
|
||||
mandate_id: item.mandate_id,
|
||||
off_session: item.off_session,
|
||||
..Self::default()
|
||||
})
|
||||
});
|
||||
request
|
||||
}
|
||||
}
|
||||
|
||||
@ -374,7 +394,7 @@ impl From<payments::PaymentsResponse> for StripePaymentIntentResponse {
|
||||
created: u64::try_from(date_time::now().assume_utc().unix_timestamp())
|
||||
.unwrap_or_default(),
|
||||
method_type: "card".to_string(),
|
||||
live_mode: false,
|
||||
livemode: false,
|
||||
},
|
||||
error_type: code,
|
||||
}),
|
||||
@ -391,7 +411,7 @@ pub struct StripePaymentMethod {
|
||||
created: u64,
|
||||
#[serde(rename = "type")]
|
||||
method_type: String,
|
||||
live_mode: bool,
|
||||
livemode: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Serialize)]
|
||||
@ -404,7 +424,7 @@ pub struct Charges {
|
||||
}
|
||||
|
||||
impl Charges {
|
||||
fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
object: "list",
|
||||
data: vec![],
|
||||
@ -491,15 +511,83 @@ impl From<payments::PaymentListResponse> for StripePaymentIntentListResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Deserialize, Clone)]
|
||||
#[derive(PartialEq, Eq, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum StripePaymentMethodOptions {
|
||||
Card {
|
||||
request_three_d_secure: Option<Request3DS>,
|
||||
mandate_options: Option<MandateOption>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum StripeMandateType {
|
||||
SingleUse,
|
||||
MultiUse,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Default, Deserialize, Serialize, Debug)]
|
||||
pub struct MandateOption {
|
||||
#[serde(default, with = "common_utils::custom_serde::timestamp::option")]
|
||||
pub accepted_at: Option<time::PrimitiveDateTime>,
|
||||
pub user_agent: Option<String>,
|
||||
pub ip_address: Option<pii::Secret<String, common_utils::pii::IpAddress>>,
|
||||
pub mandate_type: Option<StripeMandateType>,
|
||||
pub amount: Option<i64>,
|
||||
#[serde(default, with = "common_utils::custom_serde::timestamp::option")]
|
||||
pub start_date: Option<time::PrimitiveDateTime>,
|
||||
#[serde(default, with = "common_utils::custom_serde::timestamp::option")]
|
||||
pub end_date: Option<time::PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
impl ForeignTryFrom<(Option<MandateOption>, Option<String>)> for Option<payments::MandateData> {
|
||||
type Error = error_stack::Report<errors::ApiErrorResponse>;
|
||||
fn foreign_try_from(
|
||||
(mandate_options, currency): (Option<MandateOption>, Option<String>),
|
||||
) -> errors::RouterResult<Self> {
|
||||
let currency = currency
|
||||
.ok_or(errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "currency",
|
||||
})
|
||||
.into_report()
|
||||
.and_then(|c| {
|
||||
c.to_uppercase().parse_enum("currency").change_context(
|
||||
errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "currency",
|
||||
},
|
||||
)
|
||||
})?;
|
||||
let mandate_data = mandate_options.map(|mandate| payments::MandateData {
|
||||
mandate_type: match mandate.mandate_type {
|
||||
Some(item) => match item {
|
||||
StripeMandateType::SingleUse => {
|
||||
payments::MandateType::SingleUse(payments::MandateAmountData {
|
||||
amount: mandate.amount.unwrap_or_default(),
|
||||
currency,
|
||||
start_date: mandate.start_date,
|
||||
end_date: mandate.end_date,
|
||||
metadata: None,
|
||||
})
|
||||
}
|
||||
StripeMandateType::MultiUse => payments::MandateType::MultiUse(None),
|
||||
},
|
||||
None => api_models::payments::MandateType::MultiUse(None),
|
||||
},
|
||||
customer_acceptance: payments::CustomerAcceptance {
|
||||
acceptance_type: payments::AcceptanceType::Online,
|
||||
accepted_at: mandate.accepted_at,
|
||||
online: Some(payments::OnlineMandate {
|
||||
ip_address: mandate.ip_address.unwrap_or_default(),
|
||||
user_agent: mandate.user_agent.unwrap_or_default(),
|
||||
}),
|
||||
},
|
||||
});
|
||||
Ok(mandate_data)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Request3DS {
|
||||
#[default]
|
||||
|
||||
@ -28,7 +28,11 @@ pub async fn setup_intents_create(
|
||||
}
|
||||
};
|
||||
|
||||
let create_payment_req: payment_types::PaymentsRequest = payload.into();
|
||||
let create_payment_req: payment_types::PaymentsRequest =
|
||||
match payment_types::PaymentsRequest::try_from(payload) {
|
||||
Ok(req) => req,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
@ -124,7 +128,11 @@ pub async fn setup_intents_update(
|
||||
}
|
||||
};
|
||||
|
||||
let mut payload: payment_types::PaymentsRequest = stripe_payload.into();
|
||||
let mut payload: payment_types::PaymentsRequest =
|
||||
match payment_types::PaymentsRequest::try_from(stripe_payload) {
|
||||
Ok(req) => req,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));
|
||||
|
||||
let (auth_type, auth_flow) =
|
||||
@ -179,7 +187,11 @@ pub async fn setup_intents_confirm(
|
||||
}
|
||||
};
|
||||
|
||||
let mut payload: payment_types::PaymentsRequest = stripe_payload.into();
|
||||
let mut payload: payment_types::PaymentsRequest =
|
||||
match payment_types::PaymentsRequest::try_from(stripe_payload) {
|
||||
Ok(req) => req,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));
|
||||
payload.confirm = Some(true);
|
||||
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
use api_models::{payments, refunds};
|
||||
use api_models::payments;
|
||||
use common_utils::{date_time, ext_traits::StringExt};
|
||||
use error_stack::ResultExt;
|
||||
use router_env::logger;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
compatibility::stripe::{
|
||||
payment_intents::types as payment_intent, refunds::types as stripe_refunds,
|
||||
},
|
||||
consts,
|
||||
core::errors,
|
||||
pii::{self, PeekInterface},
|
||||
types::api::{self as api_types, enums as api_enums},
|
||||
types::{
|
||||
api::{self as api_types, admin, enums as api_enums},
|
||||
transformers::{ForeignFrom, ForeignTryFrom},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)]
|
||||
@ -108,11 +117,14 @@ impl From<Shipping> for payments::Address {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Deserialize, Clone)]
|
||||
|
||||
pub struct StripeSetupIntentRequest {
|
||||
pub confirm: Option<bool>,
|
||||
pub customer: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub currency: Option<String>,
|
||||
pub payment_method_data: Option<StripePaymentMethodData>,
|
||||
pub receipt_email: Option<pii::Email>,
|
||||
pub return_url: Option<url::Url>,
|
||||
@ -123,17 +135,46 @@ pub struct StripeSetupIntentRequest {
|
||||
pub statement_descriptor_suffix: Option<String>,
|
||||
pub metadata: Option<api_models::payments::Metadata>,
|
||||
pub client_secret: Option<pii::Secret<String>>,
|
||||
pub payment_method_options: Option<payment_intent::StripePaymentMethodOptions>,
|
||||
pub payment_method: Option<String>,
|
||||
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
|
||||
}
|
||||
|
||||
impl From<StripeSetupIntentRequest> for payments::PaymentsRequest {
|
||||
fn from(item: StripeSetupIntentRequest) -> Self {
|
||||
Self {
|
||||
impl TryFrom<StripeSetupIntentRequest> for payments::PaymentsRequest {
|
||||
type Error = error_stack::Report<errors::ApiErrorResponse>;
|
||||
fn try_from(item: StripeSetupIntentRequest) -> errors::RouterResult<Self> {
|
||||
let (mandate_options, authentication_type) = match item.payment_method_options {
|
||||
Some(pmo) => {
|
||||
let payment_intent::StripePaymentMethodOptions::Card {
|
||||
request_three_d_secure,
|
||||
mandate_options,
|
||||
}: payment_intent::StripePaymentMethodOptions = pmo;
|
||||
(
|
||||
Option::<payments::MandateData>::foreign_try_from((
|
||||
mandate_options,
|
||||
item.currency.to_owned(),
|
||||
))?,
|
||||
Some(api_enums::AuthenticationType::foreign_from(
|
||||
request_three_d_secure,
|
||||
)),
|
||||
)
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
let request = Ok(Self {
|
||||
amount: Some(api_types::Amount::Zero),
|
||||
currency: Some(api_enums::Currency::default()),
|
||||
capture_method: None,
|
||||
amount_to_capture: None,
|
||||
confirm: item.confirm,
|
||||
customer_id: item.customer,
|
||||
currency: item
|
||||
.currency
|
||||
.as_ref()
|
||||
.map(|c| c.to_uppercase().parse_enum("currency"))
|
||||
.transpose()
|
||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "currency",
|
||||
})?,
|
||||
email: item.receipt_email,
|
||||
name: item
|
||||
.billing_details
|
||||
@ -163,8 +204,13 @@ impl From<StripeSetupIntentRequest> for payments::PaymentsRequest {
|
||||
statement_descriptor_suffix: item.statement_descriptor_suffix,
|
||||
metadata: item.metadata,
|
||||
client_secret: item.client_secret.map(|s| s.peek().clone()),
|
||||
setup_future_usage: item.setup_future_usage,
|
||||
merchant_connector_details: item.merchant_connector_details,
|
||||
authentication_type,
|
||||
mandate_data: mandate_options,
|
||||
..Default::default()
|
||||
}
|
||||
});
|
||||
request
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,6 +278,32 @@ impl From<StripePaymentCancelRequest> for payments::PaymentsCancelRequest {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Default, Eq, PartialEq, Serialize)]
|
||||
pub struct RedirectUrl {
|
||||
pub return_url: Option<String>,
|
||||
pub url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Serialize)]
|
||||
pub struct StripeNextAction {
|
||||
#[serde(rename = "type")]
|
||||
stype: payments::NextActionType,
|
||||
redirect_to_url: RedirectUrl,
|
||||
}
|
||||
|
||||
pub(crate) fn into_stripe_next_action(
|
||||
next_action: Option<payments::NextAction>,
|
||||
return_url: Option<String>,
|
||||
) -> Option<StripeNextAction> {
|
||||
next_action.map(|n| StripeNextAction {
|
||||
stype: n.next_action_type,
|
||||
redirect_to_url: RedirectUrl {
|
||||
return_url,
|
||||
url: n.redirect_to_url,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Serialize)]
|
||||
pub struct StripeSetupIntentResponse {
|
||||
pub id: Option<String>,
|
||||
@ -241,8 +313,35 @@ pub struct StripeSetupIntentResponse {
|
||||
#[serde(with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub created: Option<time::PrimitiveDateTime>,
|
||||
pub customer: Option<String>,
|
||||
pub refunds: Option<Vec<refunds::RefundResponse>>,
|
||||
pub refunds: Option<Vec<stripe_refunds::StripeRefundResponse>>,
|
||||
pub mandate_id: Option<String>,
|
||||
pub next_action: Option<StripeNextAction>,
|
||||
pub last_payment_error: Option<LastPaymentError>,
|
||||
pub charges: payment_intent::Charges,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Serialize)]
|
||||
pub struct LastPaymentError {
|
||||
charge: Option<String>,
|
||||
code: Option<String>,
|
||||
decline_code: Option<String>,
|
||||
message: String,
|
||||
param: Option<String>,
|
||||
payment_method: StripePaymentMethod,
|
||||
#[serde(rename = "type")]
|
||||
error_type: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Serialize)]
|
||||
pub struct StripePaymentMethod {
|
||||
#[serde(rename = "id")]
|
||||
payment_method_id: String,
|
||||
object: &'static str,
|
||||
card: Option<StripeCard>,
|
||||
created: u64,
|
||||
#[serde(rename = "type")]
|
||||
method_type: String,
|
||||
livemode: bool,
|
||||
}
|
||||
|
||||
impl From<payments::PaymentsResponse> for StripeSetupIntentResponse {
|
||||
@ -251,11 +350,36 @@ impl From<payments::PaymentsResponse> for StripeSetupIntentResponse {
|
||||
object: "setup_intent".to_owned(),
|
||||
status: StripeSetupStatus::from(resp.status),
|
||||
client_secret: resp.client_secret,
|
||||
charges: payment_intent::Charges::new(),
|
||||
created: resp.created,
|
||||
customer: resp.customer_id,
|
||||
id: resp.payment_id,
|
||||
refunds: resp.refunds,
|
||||
refunds: resp
|
||||
.refunds
|
||||
.map(|a| a.into_iter().map(Into::into).collect()),
|
||||
mandate_id: resp.mandate_id,
|
||||
next_action: into_stripe_next_action(resp.next_action, resp.return_url),
|
||||
last_payment_error: resp.error_code.map(|code| -> LastPaymentError {
|
||||
LastPaymentError {
|
||||
charge: None,
|
||||
code: Some(code.to_owned()),
|
||||
decline_code: None,
|
||||
message: resp
|
||||
.error_message
|
||||
.unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
|
||||
param: None,
|
||||
payment_method: StripePaymentMethod {
|
||||
payment_method_id: "place_holder_id".to_string(),
|
||||
object: "payment_method",
|
||||
card: None,
|
||||
created: u64::try_from(date_time::now().assume_utc().unix_timestamp())
|
||||
.unwrap_or_default(),
|
||||
method_type: "card".to_string(),
|
||||
livemode: false,
|
||||
},
|
||||
error_type: code,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,6 +266,7 @@ pub struct Jwekey {
|
||||
pub locker_decryption_key2: String,
|
||||
pub vault_encryption_key: String,
|
||||
pub vault_private_key: String,
|
||||
pub tunnel_private_key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Default)]
|
||||
|
||||
@ -489,12 +489,14 @@ impl
|
||||
types::PaymentsResponseData: Clone,
|
||||
{
|
||||
let id = data.request.connector_transaction_id.clone();
|
||||
let response: transformers::PaymentIntentSyncResponse =
|
||||
match id.get_connector_transaction_id() {
|
||||
let response: transformers::PaymentIntentSyncResponse = match id
|
||||
.get_connector_transaction_id()
|
||||
{
|
||||
Ok(x) if x.starts_with("set") => res
|
||||
.response
|
||||
.parse_struct("SetupIntentSyncResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed),
|
||||
.parse_struct::<transformers::SetupIntentSyncResponse>("SetupIntentSyncResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)
|
||||
.map(Into::into),
|
||||
Ok(_) => res
|
||||
.response
|
||||
.parse_struct("PaymentIntentSyncResponse")
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use base64::Engine;
|
||||
use common_utils::{
|
||||
ext_traits::{AsyncExt, ByteSliceExt, ValueExt},
|
||||
fp_utils,
|
||||
};
|
||||
// TODO : Evaluate all the helper functions ()
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
#[cfg(feature = "kms")]
|
||||
use external_services::kms;
|
||||
use josekit::jwe;
|
||||
use masking::{ExposeOptionInterface, PeekInterface};
|
||||
use router_env::{instrument, tracing};
|
||||
use storage_models::{enums, merchant_account, payment_intent};
|
||||
@ -1546,11 +1548,12 @@ impl MerchantConnectorAccountType {
|
||||
}
|
||||
|
||||
pub async fn get_merchant_connector_account(
|
||||
db: &dyn StorageInterface,
|
||||
state: &AppState,
|
||||
merchant_id: &str,
|
||||
connector_label: &str,
|
||||
creds_identifier: Option<String>,
|
||||
) -> RouterResult<MerchantConnectorAccountType> {
|
||||
let db = &*state.store;
|
||||
match creds_identifier {
|
||||
Some(creds_identifier) => {
|
||||
let mca_config = db
|
||||
@ -1560,20 +1563,35 @@ pub async fn get_merchant_connector_account(
|
||||
errors::ApiErrorResponse::MerchantConnectorAccountNotFound,
|
||||
)?;
|
||||
|
||||
let cached_mca = consts::BASE64_ENGINE
|
||||
.decode(mca_config.config.as_bytes())
|
||||
.into_report()
|
||||
#[cfg(feature = "kms")]
|
||||
let kms_config = &state.conf.kms;
|
||||
|
||||
#[cfg(feature = "kms")]
|
||||
let private_key = kms::get_kms_client(kms_config)
|
||||
.await
|
||||
.decrypt(state.conf.jwekey.tunnel_private_key.to_owned())
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error getting tunnel private key")?;
|
||||
|
||||
#[cfg(not(feature = "kms"))]
|
||||
let private_key = state.conf.jwekey.tunnel_private_key.to_owned();
|
||||
|
||||
let decrypted_mca = services::decrypt_jwe(mca_config.config.as_str(), services::KeyIdCheck::SkipKeyIdCheck, private_key, jwe::RSA_OAEP_256)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable(
|
||||
"Failed to decode merchant_connector_details sent in request and then put in cache",
|
||||
)?
|
||||
"Failed to decrypt merchant_connector_details sent in request and then put in cache",
|
||||
)?;
|
||||
|
||||
let res = String::into_bytes(decrypted_mca)
|
||||
.parse_struct("MerchantConnectorDetails")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable(
|
||||
"Failed to parse merchant_connector_details sent in request and then put in cache",
|
||||
)?;
|
||||
|
||||
Ok(MerchantConnectorAccountType::CacheVal(cached_mca))
|
||||
Ok(MerchantConnectorAccountType::CacheVal(res))
|
||||
}
|
||||
None => db
|
||||
.find_merchant_connector_account_by_merchant_id_connector_label(
|
||||
|
||||
@ -44,9 +44,8 @@ where
|
||||
connector_id,
|
||||
);
|
||||
|
||||
let db = &*state.store;
|
||||
merchant_connector_account = helpers::get_merchant_connector_account(
|
||||
db,
|
||||
state,
|
||||
merchant_account.merchant_id.as_str(),
|
||||
&connector_label,
|
||||
payment_data.creds_identifier.to_owned(),
|
||||
@ -695,6 +694,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::VerifyRequestDat
|
||||
off_session: payment_data.mandate_id.as_ref().map(|_| true),
|
||||
mandate_id: payment_data.mandate_id.clone(),
|
||||
setup_mandate_details: payment_data.setup_mandate,
|
||||
return_url: payment_data.payment_intent.return_url,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +30,6 @@ pub async fn construct_refund_router_data<'a, F>(
|
||||
refund: &'a storage::Refund,
|
||||
creds_identifier: Option<String>,
|
||||
) -> RouterResult<types::RefundsRouterData<F>> {
|
||||
let db = &*state.store;
|
||||
|
||||
let connector_label = helpers::get_connector_label(
|
||||
payment_intent.business_country,
|
||||
&payment_intent.business_label,
|
||||
@ -40,7 +38,7 @@ pub async fn construct_refund_router_data<'a, F>(
|
||||
);
|
||||
|
||||
let merchant_connector_account = helpers::get_merchant_connector_account(
|
||||
db,
|
||||
state,
|
||||
merchant_account.merchant_id.as_str(),
|
||||
&connector_label,
|
||||
creds_identifier,
|
||||
@ -234,7 +232,6 @@ pub async fn construct_accept_dispute_router_data<'a>(
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
dispute: &storage::Dispute,
|
||||
) -> RouterResult<types::AcceptDisputeRouterData> {
|
||||
let db = &*state.store;
|
||||
let connector_id = &dispute.connector;
|
||||
let connector_label = helpers::get_connector_label(
|
||||
payment_intent.business_country,
|
||||
@ -243,7 +240,7 @@ pub async fn construct_accept_dispute_router_data<'a>(
|
||||
connector_id,
|
||||
);
|
||||
let merchant_connector_account = helpers::get_merchant_connector_account(
|
||||
db,
|
||||
state,
|
||||
merchant_account.merchant_id.as_str(),
|
||||
&connector_label,
|
||||
None,
|
||||
@ -296,7 +293,6 @@ pub async fn construct_submit_evidence_router_data<'a>(
|
||||
dispute: &storage::Dispute,
|
||||
submit_evidence_request_data: types::SubmitEvidenceRequestData,
|
||||
) -> RouterResult<types::SubmitEvidenceRouterData> {
|
||||
let db = &*state.store;
|
||||
let connector_id = &dispute.connector;
|
||||
let connector_label = helpers::get_connector_label(
|
||||
payment_intent.business_country,
|
||||
@ -305,7 +301,7 @@ pub async fn construct_submit_evidence_router_data<'a>(
|
||||
connector_id,
|
||||
);
|
||||
let merchant_connector_account = helpers::get_merchant_connector_account(
|
||||
db,
|
||||
state,
|
||||
merchant_account.merchant_id.as_str(),
|
||||
&connector_label,
|
||||
None,
|
||||
@ -356,7 +352,6 @@ pub async fn construct_upload_file_router_data<'a>(
|
||||
connector_id: &str,
|
||||
file_key: String,
|
||||
) -> RouterResult<types::UploadFileRouterData> {
|
||||
let db = &*state.store;
|
||||
let connector_label = helpers::get_connector_label(
|
||||
payment_intent.business_country,
|
||||
&payment_intent.business_label,
|
||||
@ -364,7 +359,7 @@ pub async fn construct_upload_file_router_data<'a>(
|
||||
connector_id,
|
||||
);
|
||||
let merchant_connector_account = helpers::get_merchant_connector_account(
|
||||
db,
|
||||
state,
|
||||
merchant_account.merchant_id.as_str(),
|
||||
&connector_label,
|
||||
None,
|
||||
@ -418,7 +413,7 @@ pub async fn construct_defend_dispute_router_data<'a>(
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
dispute: &storage::Dispute,
|
||||
) -> RouterResult<types::DefendDisputeRouterData> {
|
||||
let db = &*state.store;
|
||||
let _db = &*state.store;
|
||||
let connector_id = &dispute.connector;
|
||||
let connector_label = helpers::get_connector_label(
|
||||
payment_intent.business_country,
|
||||
@ -427,7 +422,7 @@ pub async fn construct_defend_dispute_router_data<'a>(
|
||||
connector_id,
|
||||
);
|
||||
let merchant_connector_account = helpers::get_merchant_connector_account(
|
||||
db,
|
||||
state,
|
||||
merchant_account.merchant_id.as_str(),
|
||||
&connector_label,
|
||||
None,
|
||||
|
||||
@ -299,6 +299,7 @@ pub struct VerifyRequestData {
|
||||
pub setup_future_usage: Option<storage_enums::FutureUsage>,
|
||||
pub off_session: Option<bool>,
|
||||
pub setup_mandate_details: Option<payments::MandateData>,
|
||||
pub return_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
Reference in New Issue
Block a user