Skip to content

Commit

Permalink
feat(payouts): make payout_type optional in payouts table (juspay#4954)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
srujanchikke and hyperswitch-bot[bot] authored Jun 12, 2024
1 parent 4651584 commit b847606
Show file tree
Hide file tree
Showing 27 changed files with 98 additions and 60 deletions.
8 changes: 6 additions & 2 deletions api-reference/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -16613,7 +16613,6 @@
"merchant_id",
"amount",
"currency",
"payout_type",
"customer_id",
"auto_fulfill",
"client_secret",
Expand Down Expand Up @@ -16656,7 +16655,12 @@
"nullable": true
},
"payout_type": {
"$ref": "#/components/schemas/PayoutType"
"allOf": [
{
"$ref": "#/components/schemas/PayoutType"
}
],
"nullable": true
},
"billing": {
"type": "object",
Expand Down
16 changes: 9 additions & 7 deletions crates/api_models/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,26 +140,28 @@ pub enum Connector {

impl Connector {
#[cfg(feature = "payouts")]
pub fn supports_instant_payout(&self, payout_method: PayoutType) -> bool {
pub fn supports_instant_payout(&self, payout_method: Option<PayoutType>) -> bool {
matches!(
(self, payout_method),
(Self::Paypal, PayoutType::Wallet) | (_, PayoutType::Card) | (Self::Adyenplatform, _)
(Self::Paypal, Some(PayoutType::Wallet))
| (_, Some(PayoutType::Card))
| (Self::Adyenplatform, _)
)
}
#[cfg(feature = "payouts")]
pub fn supports_create_recipient(&self, payout_method: PayoutType) -> bool {
matches!((self, payout_method), (_, PayoutType::Bank))
pub fn supports_create_recipient(&self, payout_method: Option<PayoutType>) -> bool {
matches!((self, payout_method), (_, Some(PayoutType::Bank)))
}
#[cfg(feature = "payouts")]
pub fn supports_payout_eligibility(&self, payout_method: PayoutType) -> bool {
matches!((self, payout_method), (_, PayoutType::Card))
pub fn supports_payout_eligibility(&self, payout_method: Option<PayoutType>) -> bool {
matches!((self, payout_method), (_, Some(PayoutType::Card)))
}
#[cfg(feature = "payouts")]
pub fn is_payout_quote_call_required(&self) -> bool {
matches!(self, Self::Wise)
}
#[cfg(feature = "payouts")]
pub fn supports_access_token_for_payout(&self, payout_method: PayoutType) -> bool {
pub fn supports_access_token_for_payout(&self, payout_method: Option<PayoutType>) -> bool {
matches!((self, payout_method), (Self::Paypal, _))
}
#[cfg(feature = "payouts")]
Expand Down
4 changes: 2 additions & 2 deletions crates/api_models/src/payouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,8 @@ pub struct PayoutCreateResponse {
pub connector: Option<String>,

/// The payout method that is to be used
#[schema(value_type = PayoutType, example = "bank")]
pub payout_type: api_enums::PayoutType,
#[schema(value_type = Option<PayoutType>, example = "bank")]
pub payout_type: Option<api_enums::PayoutType>,

/// The billing address for the payout
#[schema(value_type = Option<Object>, example = json!(r#"{
Expand Down
4 changes: 2 additions & 2 deletions crates/diesel_models/src/payouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct Payouts {
pub merchant_id: String,
pub customer_id: id_type::CustomerId,
pub address_id: String,
pub payout_type: storage_enums::PayoutType,
pub payout_type: Option<storage_enums::PayoutType>,
pub payout_method_id: Option<String>,
pub amount: i64,
pub destination_currency: storage_enums::Currency,
Expand Down Expand Up @@ -53,7 +53,7 @@ pub struct PayoutsNew {
pub merchant_id: String,
pub customer_id: id_type::CustomerId,
pub address_id: String,
pub payout_type: storage_enums::PayoutType,
pub payout_type: Option<storage_enums::PayoutType>,
pub payout_method_id: Option<String>,
pub amount: i64,
pub destination_currency: storage_enums::Currency,
Expand Down
3 changes: 2 additions & 1 deletion crates/diesel_models/src/query/payout_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,12 @@ impl PayoutAttempt {
let filter_payout_method = Payouts::table()
.select(payout_dsl::payout_type)
.distinct()
.get_results_async::<enums::PayoutType>(conn)
.get_results_async::<Option<enums::PayoutType>>(conn)
.await
.change_context(DatabaseError::Others)
.attach_printable("Error filtering records by payout type")?
.into_iter()
.flatten()
.collect::<Vec<enums::PayoutType>>();

Ok((
Expand Down
2 changes: 1 addition & 1 deletion crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,7 @@ diesel::table! {
customer_id -> Varchar,
#[max_length = 64]
address_id -> Varchar,
payout_type -> PayoutType,
payout_type -> Nullable<PayoutType>,
#[max_length = 64]
payout_method_id -> Nullable<Varchar>,
amount -> Int8,
Expand Down
6 changes: 3 additions & 3 deletions crates/hyperswitch_domain_models/src/payouts/payouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub struct Payouts {
pub merchant_id: String,
pub customer_id: id_type::CustomerId,
pub address_id: String,
pub payout_type: storage_enums::PayoutType,
pub payout_type: Option<storage_enums::PayoutType>,
pub payout_method_id: Option<String>,
pub amount: i64,
pub destination_currency: storage_enums::Currency,
Expand All @@ -99,7 +99,7 @@ pub struct PayoutsNew {
pub merchant_id: String,
pub customer_id: id_type::CustomerId,
pub address_id: String,
pub payout_type: storage_enums::PayoutType,
pub payout_type: Option<storage_enums::PayoutType>,
pub payout_method_id: Option<String>,
pub amount: i64,
pub destination_currency: storage_enums::Currency,
Expand Down Expand Up @@ -128,7 +128,7 @@ impl Default for PayoutsNew {
merchant_id: String::default(),
customer_id: common_utils::generate_customer_id_of_default_length(),
address_id: String::default(),
payout_type: storage_enums::PayoutType::default(),
payout_type: Some(storage_enums::PayoutType::default()),
payout_method_id: Option::default(),
amount: i64::default(),
destination_currency: storage_enums::Currency::default(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ pub struct PayoutsData {
pub connector_payout_id: Option<String>,
pub destination_currency: storage_enums::Currency,
pub source_currency: storage_enums::Currency,
pub payout_type: storage_enums::PayoutType,
pub payout_type: Option<storage_enums::PayoutType>,
pub entity_type: storage_enums::PayoutEntityType,
pub customer_details: Option<CustomerDetails>,
pub vendor_details: Option<api_models::payouts::PayoutVendorAccountDetails>,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/compatibility/stripe/webhooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub struct StripePayoutResponse {
pub id: String,
pub amount: i64,
pub currency: String,
pub payout_type: common_enums::PayoutType,
pub payout_type: Option<common_enums::PayoutType>,
pub status: StripePayoutStatus,
pub name: Option<masking::Secret<String>>,
pub email: Option<Email>,
Expand Down
15 changes: 13 additions & 2 deletions crates/router/src/connector/adyen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use router_env::{instrument, tracing};

use self::transformers as adyen;
use super::utils::is_mandate_supported;
#[cfg(feature = "payouts")]
use crate::connector::utils::PayoutsData;
use crate::{
capture_method_not_supported,
configs::settings,
Expand Down Expand Up @@ -1447,11 +1449,12 @@ impl services::ConnectorIntegration<api::PoFulfill, types::PayoutsData, types::P
req.test_mode,
&req.connector_meta_data,
)?;
let payout_type = req.request.get_payout_type()?;
Ok(format!(
"{}pal/servlet/Payout/{}/{}",
endpoint,
ADYEN_API_VERSION,
match req.request.payout_type {
match payout_type {
storage_enums::PayoutType::Bank | storage_enums::PayoutType::Wallet =>
"confirmThirdParty".to_string(),
storage_enums::PayoutType::Card => "payout".to_string(),
Expand All @@ -1472,9 +1475,17 @@ impl services::ConnectorIntegration<api::PoFulfill, types::PayoutsData, types::P
)];
let auth = adyen::AdyenAuthType::try_from(&req.connector_auth_type)
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
let payout_type = req
.request
.payout_type
.to_owned()
.get_required_value("payout_type")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "payout_type",
})?;
let mut api_key = vec![(
headers::X_API_KEY.to_string(),
match req.request.payout_type {
match payout_type {
storage_enums::PayoutType::Bank | storage_enums::PayoutType::Wallet => {
auth.review_key.unwrap_or(auth.api_key).into_masked()
}
Expand Down
6 changes: 3 additions & 3 deletions crates/router/src/connector/adyen/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use reqwest::Url;
use serde::{Deserialize, Serialize};
use time::{Duration, OffsetDateTime, PrimitiveDateTime};

#[cfg(feature = "payouts")]
use crate::{connector::utils::PayoutsData, types::api::payouts, utils::OptionExt};
use crate::{
connector::utils::{
self, AddressDetailsData, BrowserInformationData, CardData, MandateReferenceData,
Expand All @@ -28,8 +30,6 @@ use crate::{
},
utils as crate_utils,
};
#[cfg(feature = "payouts")]
use crate::{types::api::payouts, utils::OptionExt};

type Error = error_stack::Report<errors::ConnectorError>;

Expand Down Expand Up @@ -4757,7 +4757,7 @@ impl<F> TryFrom<&AdyenRouterData<&types::PayoutsRouterData<F>>> for AdyenPayoutF
type Error = Error;
fn try_from(item: &AdyenRouterData<&types::PayoutsRouterData<F>>) -> Result<Self, Self::Error> {
let auth_type = AdyenAuthType::try_from(&item.router_data.connector_auth_type)?;
let payout_type = item.router_data.request.payout_type.to_owned();
let payout_type = item.router_data.request.get_payout_type()?;
let merchant_account = auth_type.merchant_account;
match payout_type {
storage_enums::PayoutType::Bank | storage_enums::PayoutType::Wallet => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::Error;
use crate::{
connector::{
adyen::transformers as adyen,
utils::{self, RouterData},
utils::{self, PayoutsData, RouterData},
},
core::errors,
types::{self, api::payouts, storage::enums},
Expand Down Expand Up @@ -232,14 +232,14 @@ impl<F> TryFrom<&types::PayoutsRouterData<F>> for AdyenTransferRequest {
.ok_or(errors::ConnectorError::MissingRequiredField {
field_name: "priority",
})?;

let payout_type = request.get_payout_type()?;
Ok(Self {
amount: adyen::Amount {
value: request.amount,
currency: request.destination_currency,
},
balance_account_id,
category: AdyenPayoutMethod::try_from(request.payout_type)?,
category: AdyenPayoutMethod::try_from(payout_type)?,
counterparty,
priority: AdyenPayoutPriority::from(priority),
reference: request.payout_id.clone(),
Expand Down
5 changes: 4 additions & 1 deletion crates/router/src/connector/cybersource/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use masking::{ExposeInterface, PeekInterface, Secret};
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[cfg(feature = "payouts")]
use crate::connector::utils::PayoutsData;
use crate::{
connector::utils::{
self, AddressDetailsData, ApplePayDecrypt, CardData, PaymentsAuthorizeRequestData,
Expand Down Expand Up @@ -3152,7 +3154,8 @@ impl TryFrom<&CybersourceRouterData<&types::PayoutsRouterData<api::PoFulfill>>>
fn try_from(
item: &CybersourceRouterData<&types::PayoutsRouterData<api::PoFulfill>>,
) -> Result<Self, Self::Error> {
match item.router_data.request.payout_type {
let payout_type = item.router_data.request.get_payout_type()?;
match payout_type {
enums::PayoutType::Card => {
let client_reference_information = ClientReferenceInformation {
code: Some(item.router_data.request.payout_id.clone()),
Expand Down
6 changes: 4 additions & 2 deletions crates/router/src/connector/ebanx/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ impl<F> TryFrom<&EbanxRouterData<&types::PayoutsRouterData<F>>> for EbanxPayoutF
fn try_from(item: &EbanxRouterData<&types::PayoutsRouterData<F>>) -> Result<Self, Self::Error> {
let request = item.router_data.request.to_owned();
let ebanx_auth_type = EbanxAuthType::try_from(&item.router_data.connector_auth_type)?;
match request.payout_type.to_owned() {
let payout_type = request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Bank => Ok(Self {
integration_key: ebanx_auth_type.integration_key,
uid: request
Expand Down Expand Up @@ -330,7 +331,8 @@ impl<F> TryFrom<&types::PayoutsRouterData<F>> for EbanxPayoutCancelRequest {
fn try_from(item: &types::PayoutsRouterData<F>) -> Result<Self, Self::Error> {
let request = item.request.to_owned();
let ebanx_auth_type = EbanxAuthType::try_from(&item.connector_auth_type)?;
match request.payout_type.to_owned() {
let payout_type = request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Bank => Ok(Self {
integration_key: ebanx_auth_type.integration_key,
uid: request
Expand Down
5 changes: 3 additions & 2 deletions crates/router/src/connector/payone/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Error = error_stack::Report<errors::ConnectorError>;

#[cfg(feature = "payouts")]
use crate::{
connector::utils::{CardData, RouterData},
connector::utils::{CardData, PayoutsData, RouterData},
core::errors,
types::{self, api, storage::enums as storage_enums, transformers::ForeignFrom},
utils::OptionExt,
Expand Down Expand Up @@ -139,7 +139,8 @@ impl TryFrom<PayoneRouterData<&types::PayoutsRouterData<api::PoFulfill>>>
item: PayoneRouterData<&types::PayoutsRouterData<api::PoFulfill>>,
) -> Result<Self, Self::Error> {
let request = item.router_data.request.to_owned();
match request.payout_type.to_owned() {
let payout_type = request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Card => {
let amount_of_money: AmountOfMoney = AmountOfMoney {
amount: item.amount,
Expand Down
8 changes: 8 additions & 0 deletions crates/router/src/connector/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,8 @@ pub trait PayoutsData {
fn get_transfer_id(&self) -> Result<String, Error>;
fn get_customer_details(&self) -> Result<types::CustomerDetails, Error>;
fn get_vendor_details(&self) -> Result<PayoutVendorAccountDetails, Error>;
#[cfg(feature = "payouts")]
fn get_payout_type(&self) -> Result<storage_enums::PayoutType, Error>;
}

#[cfg(feature = "payouts")]
Expand All @@ -1188,6 +1190,12 @@ impl PayoutsData for types::PayoutsData {
.clone()
.ok_or_else(missing_field_err("vendor_details"))
}
#[cfg(feature = "payouts")]
fn get_payout_type(&self) -> Result<storage_enums::PayoutType, Error> {
self.payout_type
.to_owned()
.ok_or_else(missing_field_err("payout_type"))
}
}

#[derive(Clone, Debug, serde::Serialize)]
Expand Down
17 changes: 10 additions & 7 deletions crates/router/src/connector/wise/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Error = error_stack::Report<errors::ConnectorError>;

#[cfg(feature = "payouts")]
use crate::{
connector::utils::{self, RouterData},
connector::utils::{self, PayoutsData, RouterData},
types::{
api::payouts,
storage::enums::{self as storage_enums, PayoutEntityType},
Expand Down Expand Up @@ -352,7 +352,7 @@ impl<F> TryFrom<&types::PayoutsRouterData<F>> for WiseRecipientCreateRequest {
type Error = Error;
fn try_from(item: &types::PayoutsRouterData<F>) -> Result<Self, Self::Error> {
let request = item.request.to_owned();
let customer_details = request.customer_details;
let customer_details = request.customer_details.to_owned();
let payout_method_data = item.get_payout_method_data()?;
let bank_details = get_payout_bank_details(
payout_method_data.to_owned(),
Expand All @@ -365,7 +365,8 @@ impl<F> TryFrom<&types::PayoutsRouterData<F>> for WiseRecipientCreateRequest {
field_name: "source_id for PayoutRecipient creation",
}),
}?;
match request.payout_type.to_owned() {
let payout_type = request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Card | storage_enums::PayoutType::Wallet => {
Err(errors::ConnectorError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("Wise"),
Expand Down Expand Up @@ -421,7 +422,8 @@ impl<F> TryFrom<&types::PayoutsRouterData<F>> for WisePayoutQuoteRequest {
type Error = Error;
fn try_from(item: &types::PayoutsRouterData<F>) -> Result<Self, Self::Error> {
let request = item.request.to_owned();
match request.payout_type.to_owned() {
let payout_type = request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Bank => Ok(Self {
source_amount: Some(request.amount),
source_currency: request.source_currency.to_string(),
Expand Down Expand Up @@ -467,7 +469,8 @@ impl<F> TryFrom<&types::PayoutsRouterData<F>> for WisePayoutCreateRequest {
type Error = Error;
fn try_from(item: &types::PayoutsRouterData<F>) -> Result<Self, Self::Error> {
let request = item.request.to_owned();
match request.payout_type.to_owned() {
let payout_type = request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Bank => {
let connector_customer_id = item.get_connector_customer_id()?;
let quote_uuid = item.get_quote_id()?;
Expand Down Expand Up @@ -529,8 +532,8 @@ impl<F> TryFrom<types::PayoutsResponseRouterData<F, WisePayoutResponse>>
impl<F> TryFrom<&types::PayoutsRouterData<F>> for WisePayoutFulfillRequest {
type Error = Error;
fn try_from(item: &types::PayoutsRouterData<F>) -> Result<Self, Self::Error> {
let request = item.request.to_owned();
match request.payout_type.to_owned() {
let payout_type = item.request.get_payout_type()?;
match payout_type {
storage_enums::PayoutType::Bank => Ok(Self {
fund_type: FundType::default(),
}),
Expand Down
Loading

0 comments on commit b847606

Please sign in to comment.