mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 21:07:58 +08:00
feat(pm_auth): pm_auth service migration (#3047)
Co-authored-by: Sarthak Soni <76486416+Sarthak1799@users.noreply.github.com> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Sarthak Soni <sarthak.soni@juspay.in>
This commit is contained in:
353
crates/pm_auth/src/connector/plaid.rs
Normal file
353
crates/pm_auth/src/connector/plaid.rs
Normal file
@ -0,0 +1,353 @@
|
||||
pub mod transformers;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use common_utils::{
|
||||
ext_traits::{BytesExt, Encode},
|
||||
request::{Method, Request, RequestBody, RequestBuilder},
|
||||
};
|
||||
use error_stack::ResultExt;
|
||||
use masking::{Mask, Maskable};
|
||||
use transformers as plaid;
|
||||
|
||||
use crate::{
|
||||
core::errors,
|
||||
types::{
|
||||
self as auth_types,
|
||||
api::{
|
||||
auth_service::{self, BankAccountCredentials, ExchangeToken, LinkToken},
|
||||
ConnectorCommon, ConnectorCommonExt, ConnectorIntegration,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Plaid;
|
||||
|
||||
impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Plaid
|
||||
where
|
||||
Self: ConnectorIntegration<Flow, Request, Response>,
|
||||
{
|
||||
fn build_headers(
|
||||
&self,
|
||||
req: &auth_types::PaymentAuthRouterData<Flow, Request, Response>,
|
||||
_connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
|
||||
let mut header = vec![(
|
||||
"Content-Type".to_string(),
|
||||
self.get_content_type().to_string().into(),
|
||||
)];
|
||||
|
||||
let mut auth = self.get_auth_header(&req.connector_auth_type)?;
|
||||
header.append(&mut auth);
|
||||
Ok(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorCommon for Plaid {
|
||||
fn id(&self) -> &'static str {
|
||||
"plaid"
|
||||
}
|
||||
|
||||
fn common_get_content_type(&self) -> &'static str {
|
||||
"application/json"
|
||||
}
|
||||
fn base_url<'a>(&self, _connectors: &'a auth_types::PaymentMethodAuthConnectors) -> &'a str {
|
||||
"https://sandbox.plaid.com"
|
||||
}
|
||||
|
||||
fn get_auth_header(
|
||||
&self,
|
||||
auth_type: &auth_types::ConnectorAuthType,
|
||||
) -> errors::CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
|
||||
let auth = plaid::PlaidAuthType::try_from(auth_type)
|
||||
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
|
||||
let client_id = auth.client_id.into_masked();
|
||||
let secret = auth.secret.into_masked();
|
||||
|
||||
Ok(vec![
|
||||
("PLAID-CLIENT-ID".to_string(), client_id),
|
||||
("PLAID-SECRET".to_string(), secret),
|
||||
])
|
||||
}
|
||||
|
||||
fn build_error_response(
|
||||
&self,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::ErrorResponse, errors::ConnectorError> {
|
||||
let response: plaid::PlaidErrorResponse =
|
||||
res.response
|
||||
.parse_struct("PlaidErrorResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
Ok(auth_types::ErrorResponse {
|
||||
status_code: res.status_code,
|
||||
code: crate::consts::NO_ERROR_CODE.to_string(),
|
||||
message: response.error_message,
|
||||
reason: response.display_message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl auth_service::AuthService for Plaid {}
|
||||
impl auth_service::AuthServiceLinkToken for Plaid {}
|
||||
|
||||
impl ConnectorIntegration<LinkToken, auth_types::LinkTokenRequest, auth_types::LinkTokenResponse>
|
||||
for Plaid
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &auth_types::LinkTokenRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &auth_types::LinkTokenRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<String, errors::ConnectorError> {
|
||||
Ok(format!(
|
||||
"{}{}",
|
||||
self.base_url(connectors),
|
||||
"/link/token/create"
|
||||
))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &auth_types::LinkTokenRouterData,
|
||||
) -> errors::CustomResult<Option<RequestBody>, errors::ConnectorError> {
|
||||
let req_obj = plaid::PlaidLinkTokenRequest::try_from(req)?;
|
||||
let plaid_req = RequestBody::log_and_get_request_body(
|
||||
&req_obj,
|
||||
Encode::<plaid::PlaidLinkTokenRequest>::encode_to_string_of_json,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(plaid_req))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &auth_types::LinkTokenRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Option<Request>, errors::ConnectorError> {
|
||||
Ok(Some(
|
||||
RequestBuilder::new()
|
||||
.method(Method::Post)
|
||||
.url(&auth_types::PaymentAuthLinkTokenType::get_url(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.attach_default_headers()
|
||||
.headers(auth_types::PaymentAuthLinkTokenType::get_headers(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.body(auth_types::PaymentAuthLinkTokenType::get_request_body(
|
||||
self, req,
|
||||
)?)
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &auth_types::LinkTokenRouterData,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::LinkTokenRouterData, errors::ConnectorError> {
|
||||
let response: plaid::PlaidLinkTokenResponse = res
|
||||
.response
|
||||
.parse_struct("PlaidLinkTokenResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
<auth_types::LinkTokenRouterData>::try_from(auth_types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
}
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::ErrorResponse, errors::ConnectorError> {
|
||||
self.build_error_response(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl auth_service::AuthServiceExchangeToken for Plaid {}
|
||||
|
||||
impl
|
||||
ConnectorIntegration<
|
||||
ExchangeToken,
|
||||
auth_types::ExchangeTokenRequest,
|
||||
auth_types::ExchangeTokenResponse,
|
||||
> for Plaid
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &auth_types::ExchangeTokenRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &auth_types::ExchangeTokenRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<String, errors::ConnectorError> {
|
||||
Ok(format!(
|
||||
"{}{}",
|
||||
self.base_url(connectors),
|
||||
"/item/public_token/exchange"
|
||||
))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &auth_types::ExchangeTokenRouterData,
|
||||
) -> errors::CustomResult<Option<RequestBody>, errors::ConnectorError> {
|
||||
let req_obj = plaid::PlaidExchangeTokenRequest::try_from(req)?;
|
||||
let plaid_req = RequestBody::log_and_get_request_body(
|
||||
&req_obj,
|
||||
Encode::<plaid::PlaidExchangeTokenRequest>::encode_to_string_of_json,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(plaid_req))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &auth_types::ExchangeTokenRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Option<Request>, errors::ConnectorError> {
|
||||
Ok(Some(
|
||||
RequestBuilder::new()
|
||||
.method(Method::Post)
|
||||
.url(&auth_types::PaymentAuthExchangeTokenType::get_url(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.attach_default_headers()
|
||||
.headers(auth_types::PaymentAuthExchangeTokenType::get_headers(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.body(auth_types::PaymentAuthExchangeTokenType::get_request_body(
|
||||
self, req,
|
||||
)?)
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &auth_types::ExchangeTokenRouterData,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::ExchangeTokenRouterData, errors::ConnectorError> {
|
||||
let response: plaid::PlaidExchangeTokenResponse = res
|
||||
.response
|
||||
.parse_struct("PlaidExchangeTokenResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
<auth_types::ExchangeTokenRouterData>::try_from(auth_types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
}
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::ErrorResponse, errors::ConnectorError> {
|
||||
self.build_error_response(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl auth_service::AuthServiceBankAccountCredentials for Plaid {}
|
||||
|
||||
impl
|
||||
ConnectorIntegration<
|
||||
BankAccountCredentials,
|
||||
auth_types::BankAccountCredentialsRequest,
|
||||
auth_types::BankAccountCredentialsResponse,
|
||||
> for Plaid
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &auth_types::BankDetailsRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &auth_types::BankDetailsRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<String, errors::ConnectorError> {
|
||||
Ok(format!("{}{}", self.base_url(connectors), "/auth/get"))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &auth_types::BankDetailsRouterData,
|
||||
) -> errors::CustomResult<Option<RequestBody>, errors::ConnectorError> {
|
||||
let req_obj = plaid::PlaidBankAccountCredentialsRequest::try_from(req)?;
|
||||
let plaid_req = RequestBody::log_and_get_request_body(
|
||||
&req_obj,
|
||||
Encode::<plaid::PlaidBankAccountCredentialsRequest>::encode_to_string_of_json,
|
||||
)
|
||||
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
|
||||
Ok(Some(plaid_req))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &auth_types::BankDetailsRouterData,
|
||||
connectors: &auth_types::PaymentMethodAuthConnectors,
|
||||
) -> errors::CustomResult<Option<Request>, errors::ConnectorError> {
|
||||
Ok(Some(
|
||||
RequestBuilder::new()
|
||||
.method(Method::Post)
|
||||
.url(&auth_types::PaymentAuthBankAccountDetailsType::get_url(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.attach_default_headers()
|
||||
.headers(auth_types::PaymentAuthBankAccountDetailsType::get_headers(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.body(auth_types::PaymentAuthBankAccountDetailsType::get_request_body(self, req)?)
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &auth_types::BankDetailsRouterData,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::BankDetailsRouterData, errors::ConnectorError> {
|
||||
let response: plaid::PlaidBankAccountCredentialsResponse = res
|
||||
.response
|
||||
.parse_struct("PlaidBankAccountCredentialsResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
<auth_types::BankDetailsRouterData>::try_from(auth_types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
}
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: auth_types::Response,
|
||||
) -> errors::CustomResult<auth_types::ErrorResponse, errors::ConnectorError> {
|
||||
self.build_error_response(res)
|
||||
}
|
||||
}
|
||||
294
crates/pm_auth/src/connector/plaid/transformers.rs
Normal file
294
crates/pm_auth/src/connector/plaid/transformers.rs
Normal file
@ -0,0 +1,294 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use common_enums::PaymentMethodType;
|
||||
use masking::Secret;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{core::errors, types};
|
||||
|
||||
#[derive(Debug, Serialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PlaidLinkTokenRequest {
|
||||
client_name: String,
|
||||
country_codes: Vec<String>,
|
||||
language: String,
|
||||
products: Vec<String>,
|
||||
user: User,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Eq, PartialEq)]
|
||||
|
||||
pub struct User {
|
||||
pub client_user_id: String,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::LinkTokenRouterData> for PlaidLinkTokenRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::LinkTokenRouterData) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
client_name: item.request.client_name.clone(),
|
||||
country_codes: item.request.country_codes.clone().ok_or(
|
||||
errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "country_codes",
|
||||
},
|
||||
)?,
|
||||
language: item.request.language.clone().unwrap_or("en".to_string()),
|
||||
products: vec!["auth".to_string()],
|
||||
user: User {
|
||||
client_user_id: item.request.user_info.clone().ok_or(
|
||||
errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "country_codes",
|
||||
},
|
||||
)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PlaidLinkTokenResponse {
|
||||
link_token: String,
|
||||
}
|
||||
|
||||
impl<F, T>
|
||||
TryFrom<types::ResponseRouterData<F, PlaidLinkTokenResponse, T, types::LinkTokenResponse>>
|
||||
for types::PaymentAuthRouterData<F, T, types::LinkTokenResponse>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<F, PlaidLinkTokenResponse, T, types::LinkTokenResponse>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
response: Ok(types::LinkTokenResponse {
|
||||
link_token: item.response.link_token,
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PlaidExchangeTokenRequest {
|
||||
public_token: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
|
||||
pub struct PlaidExchangeTokenResponse {
|
||||
pub access_token: String,
|
||||
}
|
||||
|
||||
impl<F, T>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<F, PlaidExchangeTokenResponse, T, types::ExchangeTokenResponse>,
|
||||
> for types::PaymentAuthRouterData<F, T, types::ExchangeTokenResponse>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<
|
||||
F,
|
||||
PlaidExchangeTokenResponse,
|
||||
T,
|
||||
types::ExchangeTokenResponse,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
response: Ok(types::ExchangeTokenResponse {
|
||||
access_token: item.response.access_token,
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&types::ExchangeTokenRouterData> for PlaidExchangeTokenRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::ExchangeTokenRouterData) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
public_token: item.request.public_token.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PlaidBankAccountCredentialsRequest {
|
||||
access_token: String,
|
||||
options: Option<BankAccountCredentialsOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
|
||||
pub struct PlaidBankAccountCredentialsResponse {
|
||||
pub accounts: Vec<PlaidBankAccountCredentialsAccounts>,
|
||||
pub numbers: PlaidBankAccountCredentialsNumbers,
|
||||
// pub item: PlaidBankAccountCredentialsItem,
|
||||
pub request_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Eq, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct BankAccountCredentialsOptions {
|
||||
account_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
|
||||
pub struct PlaidBankAccountCredentialsAccounts {
|
||||
pub account_id: String,
|
||||
pub name: String,
|
||||
pub subtype: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsBalances {
|
||||
pub available: Option<i32>,
|
||||
pub current: Option<i32>,
|
||||
pub limit: Option<i32>,
|
||||
pub iso_currency_code: Option<String>,
|
||||
pub unofficial_currency_code: Option<String>,
|
||||
pub last_updated_datetime: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsNumbers {
|
||||
pub ach: Vec<PlaidBankAccountCredentialsACH>,
|
||||
pub eft: Vec<PlaidBankAccountCredentialsEFT>,
|
||||
pub international: Vec<PlaidBankAccountCredentialsInternational>,
|
||||
pub bacs: Vec<PlaidBankAccountCredentialsBacs>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsItem {
|
||||
pub item_id: String,
|
||||
pub institution_id: Option<String>,
|
||||
pub webhook: Option<String>,
|
||||
pub error: Option<PlaidErrorResponse>,
|
||||
}
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsACH {
|
||||
pub account_id: String,
|
||||
pub account: String,
|
||||
pub routing: String,
|
||||
pub wire_routing: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsEFT {
|
||||
pub account_id: String,
|
||||
pub account: String,
|
||||
pub institution: String,
|
||||
pub branch: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsInternational {
|
||||
pub account_id: String,
|
||||
pub iban: String,
|
||||
pub bic: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Eq, PartialEq)]
|
||||
pub struct PlaidBankAccountCredentialsBacs {
|
||||
pub account_id: String,
|
||||
pub account: String,
|
||||
pub sort_code: String,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::BankDetailsRouterData> for PlaidBankAccountCredentialsRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::BankDetailsRouterData) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
access_token: item.request.access_token.clone(),
|
||||
options: item.request.optional_ids.as_ref().map(|bank_account_ids| {
|
||||
BankAccountCredentialsOptions {
|
||||
account_ids: bank_account_ids.ids.clone(),
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<
|
||||
F,
|
||||
PlaidBankAccountCredentialsResponse,
|
||||
T,
|
||||
types::BankAccountCredentialsResponse,
|
||||
>,
|
||||
> for types::PaymentAuthRouterData<F, T, types::BankAccountCredentialsResponse>
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<
|
||||
F,
|
||||
PlaidBankAccountCredentialsResponse,
|
||||
T,
|
||||
types::BankAccountCredentialsResponse,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (account_numbers, accounts_info) = (item.response.numbers, item.response.accounts);
|
||||
let mut bank_account_vec = Vec::new();
|
||||
let mut id_to_suptype = HashMap::new();
|
||||
|
||||
accounts_info.into_iter().for_each(|acc| {
|
||||
id_to_suptype.insert(acc.account_id, (acc.subtype, acc.name));
|
||||
});
|
||||
|
||||
account_numbers.ach.into_iter().for_each(|ach| {
|
||||
let (acc_type, acc_name) =
|
||||
if let Some((_type, name)) = id_to_suptype.get(&ach.account_id) {
|
||||
(_type.to_owned(), Some(name.clone()))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let bank_details_new = types::BankAccountDetails {
|
||||
account_name: acc_name,
|
||||
account_number: ach.account,
|
||||
routing_number: ach.routing,
|
||||
payment_method_type: PaymentMethodType::Ach,
|
||||
account_id: ach.account_id,
|
||||
account_type: acc_type,
|
||||
};
|
||||
|
||||
bank_account_vec.push(bank_details_new);
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
response: Ok(types::BankAccountCredentialsResponse {
|
||||
credentials: bank_account_vec,
|
||||
}),
|
||||
..item.data
|
||||
})
|
||||
}
|
||||
}
|
||||
pub struct PlaidAuthType {
|
||||
pub client_id: Secret<String>,
|
||||
pub secret: Secret<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::ConnectorAuthType> for PlaidAuthType {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
|
||||
match auth_type {
|
||||
types::ConnectorAuthType::BodyKey { client_id, secret } => Ok(Self {
|
||||
client_id: client_id.to_owned(),
|
||||
secret: secret.to_owned(),
|
||||
}),
|
||||
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct PlaidErrorResponse {
|
||||
pub display_message: Option<String>,
|
||||
pub error_code: Option<String>,
|
||||
pub error_message: String,
|
||||
pub error_type: Option<String>,
|
||||
}
|
||||
Reference in New Issue
Block a user