feat: stripe connect integration for payouts (#2041)

Co-authored-by: Rachit Naithani <81706961+racnan@users.noreply.github.com>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Apoorv Dixit <64925866+apoorvdixit88@users.noreply.github.com>
Co-authored-by: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com>
Co-authored-by: Narayan Bhat <narayan.bhat@juspay.in>
Co-authored-by: Shankar Singh C <83439957+ShankarSinghC@users.noreply.github.com>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Sakil Mostak <73734619+Sakilmostak@users.noreply.github.com>
Co-authored-by: AkshayaFoiger <131388445+AkshayaFoiger@users.noreply.github.com>
This commit is contained in:
Kashif
2024-04-29 15:29:32 +05:30
committed by GitHub
parent 79d8949413
commit ac9d856add
40 changed files with 1782 additions and 272 deletions

View File

@ -1,11 +1,15 @@
use std::{marker::PhantomData, str::FromStr};
use api_models::enums::{DisputeStage, DisputeStatus};
#[cfg(feature = "payouts")]
use api_models::payouts::PayoutVendorAccountDetails;
use common_enums::{IntentStatus, RequestIncrementalAuthorization};
#[cfg(feature = "payouts")]
use common_utils::{crypto::Encryptable, pii::Email};
use common_utils::{errors::CustomResult, ext_traits::AsyncExt};
use error_stack::{report, ResultExt};
#[cfg(feature = "payouts")]
use masking::PeekInterface;
use maud::{html, PreEscaped};
use router_env::{instrument, tracing};
use uuid::Uuid;
@ -31,6 +35,9 @@ use crate::{
pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_DISPUTE_FLOW: &str =
"irrelevant_connector_request_reference_id_in_dispute_flow";
#[cfg(feature = "payouts")]
pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_PAYOUTS_FLOW: &str =
"irrelevant_connector_request_reference_id_in_payouts_flow";
const IRRELEVANT_PAYMENT_ID_IN_DISPUTE_FLOW: &str = "irrelevant_payment_id_in_dispute_flow";
const IRRELEVANT_ATTEMPT_ID_IN_DISPUTE_FLOW: &str = "irrelevant_attempt_id_in_dispute_flow";
@ -65,15 +72,14 @@ pub async fn get_mca_for_payout<'a>(
#[instrument(skip_all)]
pub async fn construct_payout_router_data<'a, F>(
state: &'a AppState,
connector_id: &str,
connector_name: &api_models::enums::Connector,
merchant_account: &domain::MerchantAccount,
key_store: &domain::MerchantKeyStore,
_request: &api_models::payouts::PayoutRequest,
payout_data: &mut PayoutData,
) -> RouterResult<types::PayoutsRouterData<F>> {
let merchant_connector_account = get_mca_for_payout(
state,
connector_id,
&connector_name.to_string(),
merchant_account,
key_store,
payout_data,
@ -117,25 +123,36 @@ pub async fn construct_payout_router_data<'a, F>(
let payouts = &payout_data.payouts;
let payout_attempt = &payout_data.payout_attempt;
let customer_details = &payout_data.customer_details;
let connector_name = payout_attempt
.connector
.clone()
.get_required_value("connector")
.change_context(errors::ApiErrorResponse::InvalidRequestData {
message: "Could not decide to route the connector".to_string(),
})?;
let connector_label = format!("{}_{}", payout_data.profile_id, connector_name);
let connector_customer_id = customer_details
.as_ref()
.and_then(|c| c.connector_customer.as_ref())
.and_then(|cc| cc.get(connector_label))
.and_then(|id| serde_json::from_value::<String>(id.to_owned()).ok());
let vendor_details: Option<PayoutVendorAccountDetails> =
match api_models::enums::PayoutConnectors::try_from(connector_name.to_owned()).map_err(
|err| report!(errors::ApiErrorResponse::InternalServerError).attach_printable(err),
)? {
api_models::enums::PayoutConnectors::Stripe => {
payout_data.payouts.metadata.to_owned().and_then(|meta| {
let val = meta
.peek()
.to_owned()
.parse_value("PayoutVendorAccountDetails")
.ok();
val
})
}
_ => None,
};
let router_data = types::RouterData {
flow: PhantomData,
merchant_id: merchant_account.merchant_id.to_owned(),
customer_id: None,
connector_customer: connector_customer_id,
connector: connector_id.to_string(),
connector: connector_name.to_string(),
payment_id: "".to_string(),
attempt_id: "".to_string(),
status: enums::AttemptStatus::Failure,
@ -157,6 +174,7 @@ pub async fn construct_payout_router_data<'a, F>(
source_currency: payouts.source_currency,
entity_type: payouts.entity_type.to_owned(),
payout_type: payouts.payout_type,
vendor_details,
customer_details: customer_details
.to_owned()
.map(|c| payments::CustomerDetails {
@ -174,7 +192,7 @@ pub async fn construct_payout_router_data<'a, F>(
payment_method_token: None,
recurring_mandate_payment_data: None,
preprocessing_id: None,
connector_request_reference_id: IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_DISPUTE_FLOW
connector_request_reference_id: IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_PAYOUTS_FLOW
.to_string(),
payout_method_data: payout_data.payout_method_data.to_owned(),
quote_id: None,