feat(payouts): add payout types in euclid crate (#3862)

Co-authored-by: Kashif <mohammed.kashif@juspay.in>
This commit is contained in:
Kashif
2024-03-21 14:26:49 +05:30
committed by GitHub
parent fb5f0e6c7e
commit a151485317
11 changed files with 278 additions and 19 deletions

View File

@ -2057,12 +2057,15 @@ pub enum PayoutStatus {
Debug,
Default,
Eq,
Hash,
PartialEq,
ToSchema,
serde::Deserialize,
serde::Serialize,
strum::Display,
strum::EnumVariantNames,
strum::EnumIter,
strum::EnumString,
ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]

View File

@ -23,10 +23,12 @@ common_enums = { version = "0.1.0", path = "../common_enums" }
euclid_macros = { version = "0.1.0", path = "../euclid_macros" }
[features]
default = []
ast_parser = ["dep:nom"]
valued_jit = []
connector_choice_mca_id = []
dummy_connector = []
payouts = []
[dev-dependencies]
criterion = "0.5"

View File

@ -34,6 +34,12 @@ collect_variants!(CaptureMethod);
collect_variants!(Currency);
collect_variants!(Country);
collect_variants!(SetupFutureUsage);
#[cfg(feature = "payouts")]
collect_variants!(PayoutType);
#[cfg(feature = "payouts")]
collect_variants!(PayoutBankTransferType);
#[cfg(feature = "payouts")]
collect_variants!(PayoutWalletType);
#[derive(
Clone,
@ -94,3 +100,67 @@ pub enum MandateType {
SingleUse,
MultiUse,
}
#[cfg(feature = "payouts")]
#[derive(
Clone,
Debug,
Hash,
PartialEq,
Eq,
strum::Display,
strum::EnumVariantNames,
strum::EnumIter,
strum::EnumString,
serde::Serialize,
serde::Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PayoutBankTransferType {
Ach,
Bacs,
Sepa,
}
#[cfg(feature = "payouts")]
#[derive(
Clone,
Debug,
Hash,
PartialEq,
Eq,
strum::Display,
strum::EnumVariantNames,
strum::EnumIter,
strum::EnumString,
serde::Serialize,
serde::Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PayoutWalletType {
Paypal,
}
#[cfg(feature = "payouts")]
#[derive(
Clone,
Debug,
Hash,
PartialEq,
Eq,
strum::Display,
strum::EnumVariantNames,
strum::EnumIter,
strum::EnumString,
serde::Serialize,
serde::Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PayoutType {
Card,
BankTransfer,
Wallet,
}

View File

@ -667,6 +667,101 @@ impl DirValue {
}
}
#[cfg(feature = "payouts")]
#[derive(
Debug,
Clone,
Hash,
PartialEq,
Eq,
serde::Serialize,
strum::Display,
strum::EnumIter,
strum::EnumVariantNames,
strum::EnumString,
strum::EnumMessage,
strum::EnumProperty,
)]
pub enum PayoutDirKeyKind {
#[strum(
serialize = "country",
serialize = "business_country",
detailed_message = "Country of the business unit",
props(Category = "Merchant")
)]
#[serde(rename = "business_country", alias = "country")]
BusinessCountry,
#[strum(
serialize = "billing_country",
detailed_message = "Country of the billing address of the customer",
props(Category = "Customer")
)]
#[serde(rename = "billing_country")]
BillingCountry,
#[strum(
serialize = "business_label",
detailed_message = "Identifier for business unit",
props(Category = "Merchant")
)]
#[serde(rename = "business_label")]
BusinessLabel,
#[strum(
serialize = "amount",
detailed_message = "Value of the transaction",
props(Category = "Order details")
)]
#[serde(rename = "amount")]
PayoutAmount,
#[strum(
serialize = "payment_method",
detailed_message = "Different modes of payout - eg. cards, wallets, banks",
props(Category = "Payout Methods")
)]
#[serde(rename = "payment_method")]
PayoutType,
#[strum(
serialize = "wallet",
detailed_message = "Supported types of Wallets for payouts",
props(Category = "Payout Methods Type")
)]
#[serde(rename = "wallet")]
WalletType,
#[strum(
serialize = "bank_transfer",
detailed_message = "Supported types of Bank transfer types for payouts",
props(Category = "Payout Methods Type")
)]
#[serde(rename = "bank_transfer")]
BankTransferType,
}
#[cfg(feature = "payouts")]
#[derive(
Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, strum::Display, strum::EnumVariantNames,
)]
pub enum PayoutDirValue {
#[serde(rename = "business_country", alias = "country")]
BusinessCountry(enums::Country),
#[serde(rename = "billing_country")]
BillingCountry(enums::Country),
#[serde(rename = "business_label")]
BusinessLabel(types::StrValue),
#[serde(rename = "amount")]
PayoutAmount(types::NumValue),
#[serde(rename = "payment_method")]
PayoutType(common_enums::PayoutType),
#[serde(rename = "wallet")]
WalletType(enums::PayoutWalletType),
#[serde(rename = "bank_transfer")]
BankTransferType(enums::PayoutBankTransferType),
}
#[derive(Debug, Clone)]
pub enum DirComparisonLogic {
NegativeConjunction,

View File

@ -6,6 +6,8 @@ pub use crate::enums::{
Country as BillingCountry, Currency as PaymentCurrency, MandateAcceptanceType, MandateType,
PaymentMethod, PaymentType, RoutableConnectors, SetupFutureUsage,
};
#[cfg(feature = "payouts")]
pub use crate::enums::{PayoutBankTransferType, PayoutType, PayoutWalletType};
#[derive(
Clone,

View File

@ -11,14 +11,14 @@ crate-type = ["cdylib"]
[features]
default = ["connector_choice_bcompat", "payouts", "connector_choice_mca_id"]
release = ["connector_choice_bcompat", "connector_choice_mca_id"]
release = ["connector_choice_bcompat", "connector_choice_mca_id", "payouts"]
connector_choice_bcompat = ["api_models/connector_choice_bcompat"]
connector_choice_mca_id = ["api_models/connector_choice_mca_id", "euclid/connector_choice_mca_id", "kgraph_utils/connector_choice_mca_id"]
dummy_connector = ["kgraph_utils/dummy_connector", "connector_configs/dummy_connector"]
production = ["connector_configs/production"]
development = ["connector_configs/development"]
sandbox = ["connector_configs/sandbox"]
payouts = ["api_models/payouts"]
payouts = ["api_models/payouts", "euclid/payouts"]
[dependencies]
api_models = { version = "0.1.0", path = "../api_models", package = "api_models" }

View File

@ -256,12 +256,13 @@ pub fn get_variant_values(key: &str) -> Result<JsValue, JsValue> {
dir::DirKeyKind::CardRedirectType => dir_enums::CardRedirectType::VARIANTS,
dir::DirKeyKind::GiftCardType => dir_enums::GiftCardType::VARIANTS,
dir::DirKeyKind::VoucherType => dir_enums::VoucherType::VARIANTS,
dir::DirKeyKind::BankDebitType => dir_enums::BankDebitType::VARIANTS,
dir::DirKeyKind::PaymentAmount
| dir::DirKeyKind::Connector
| dir::DirKeyKind::CardBin
| dir::DirKeyKind::BusinessLabel
| dir::DirKeyKind::MetaData => Err("Key does not have variants".to_string())?,
dir::DirKeyKind::BankDebitType => dir_enums::BankDebitType::VARIANTS,
};
Ok(serde_wasm_bindgen::to_value(variants)?)
@ -335,3 +336,52 @@ pub fn get_response_payload(input: JsValue) -> JsResult {
let result = ConnectorApiIntegrationPayload::get_transformed_response_payload(input);
Ok(serde_wasm_bindgen::to_value(&result)?)
}
#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getAllPayoutKeys)]
pub fn get_all_payout_keys() -> JsResult {
let keys: Vec<&'static str> = dir::PayoutDirKeyKind::VARIANTS.to_vec();
Ok(serde_wasm_bindgen::to_value(&keys)?)
}
#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getPayoutVariantValues)]
pub fn get_payout_variant_values(key: &str) -> Result<JsValue, JsValue> {
let key =
dir::PayoutDirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;
let variants: &[&str] = match key {
dir::PayoutDirKeyKind::BusinessCountry => dir_enums::BusinessCountry::VARIANTS,
dir::PayoutDirKeyKind::BillingCountry => dir_enums::BillingCountry::VARIANTS,
dir::PayoutDirKeyKind::PayoutType => dir_enums::PayoutType::VARIANTS,
dir::PayoutDirKeyKind::WalletType => dir_enums::PayoutWalletType::VARIANTS,
dir::PayoutDirKeyKind::BankTransferType => dir_enums::PayoutBankTransferType::VARIANTS,
dir::PayoutDirKeyKind::PayoutAmount | dir::PayoutDirKeyKind::BusinessLabel => {
Err("Key does not have variants".to_string())?
}
};
Ok(serde_wasm_bindgen::to_value(variants)?)
}
#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getPayoutDescriptionCategory)]
pub fn get_payout_description_category() -> JsResult {
let keys = dir::PayoutDirKeyKind::VARIANTS.to_vec();
let mut category: HashMap<Option<&str>, Vec<types::PayoutDetails<'_>>> = HashMap::new();
for key in keys {
let dir_key =
dir::PayoutDirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;
let details = types::PayoutDetails {
description: dir_key.get_detailed_message(),
kind: dir_key.clone(),
};
category
.entry(dir_key.get_str("Category"))
.and_modify(|val| val.push(details.clone()))
.or_insert(vec![details]);
}
Ok(serde_wasm_bindgen::to_value(&category)?)
}

View File

@ -1,4 +1,6 @@
use euclid::frontend::dir::DirKeyKind;
#[cfg(feature = "payouts")]
use euclid::frontend::dir::PayoutDirKeyKind;
use serde::Serialize;
#[derive(Serialize, Clone)]
@ -6,3 +8,10 @@ pub struct Details<'a> {
pub description: Option<&'a str>,
pub kind: DirKeyKind,
}
#[cfg(feature = "payouts")]
#[derive(Serialize, Clone)]
pub struct PayoutDetails<'a> {
pub description: Option<&'a str>,
pub kind: PayoutDirKeyKind,
}

View File

@ -714,6 +714,7 @@ pub async fn retrieve_linked_routing_config(
state: AppState,
merchant_account: domain::MerchantAccount,
#[cfg(feature = "business_profile_routing")] query_params: RoutingRetrieveLinkQuery,
#[cfg(feature = "business_profile_routing")] transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::LinkedRoutingConfigRetrieveResponse> {
metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(&metrics::CONTEXT, 1, &[]);
let db = state.store.as_ref();
@ -739,16 +740,17 @@ pub async fn retrieve_linked_routing_config(
let mut active_algorithms = Vec::new();
for business_profile in business_profiles {
let routing_ref: routing_types::RoutingAlgorithmRef = business_profile
.routing_algorithm
.clone()
.map(|val| val.parse_value("RoutingAlgorithmRef"))
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable(
"unable to deserialize routing algorithm ref from merchant account",
)?
.unwrap_or_default();
let routing_ref: routing_types::RoutingAlgorithmRef = match transaction_type {
enums::TransactionType::Payment => business_profile.routing_algorithm,
#[cfg(feature = "payouts")]
enums::TransactionType::Payout => business_profile.payout_routing_algorithm,
}
.clone()
.map(|val| val.parse_value("RoutingAlgorithmRef"))
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("unable to deserialize routing algorithm ref from merchant account")?
.unwrap_or_default();
if let Some(algorithm_id) = routing_ref.algorithm_id {
let record = db

View File

@ -401,10 +401,18 @@ impl Routing {
#[allow(unused_mut)]
let mut route = web::scope("/routing")
.app_data(web::Data::new(state.clone()))
.service(
web::resource("/active")
.route(web::get().to(cloud_routing::routing_retrieve_linked_config)),
)
.service(web::resource("/active").route(web::get().to(
|state, req, #[cfg(feature = "business_profile_routing")] query_params| {
cloud_routing::routing_retrieve_linked_config(
state,
req,
#[cfg(feature = "business_profile_routing")]
query_params,
#[cfg(feature = "business_profile_routing")]
&TransactionType::Payment,
)
},
)))
.service(
web::resource("")
.route(
@ -524,6 +532,18 @@ impl Routing {
)
})),
)
.service(web::resource("/payouts/active").route(web::get().to(
|state, req, #[cfg(feature = "business_profile_routing")] query_params| {
cloud_routing::routing_retrieve_linked_config(
state,
req,
#[cfg(feature = "business_profile_routing")]
query_params,
#[cfg(feature = "business_profile_routing")]
&TransactionType::Payout,
)
},
)))
.service(
web::resource("/payouts/default")
.route(web::get().to(|state, req| {

View File

@ -509,6 +509,7 @@ pub async fn routing_retrieve_linked_config(
state: web::Data<AppState>,
req: HttpRequest,
#[cfg(feature = "business_profile_routing")] query: web::Query<RoutingRetrieveLinkQuery>,
#[cfg(feature = "business_profile_routing")] transaction_type: &enums::TransactionType,
) -> impl Responder {
#[cfg(feature = "business_profile_routing")]
{
@ -520,7 +521,12 @@ pub async fn routing_retrieve_linked_config(
&req,
query.into_inner(),
|state, auth: AuthenticationData, query_params| {
routing::retrieve_linked_routing_config(state, auth.merchant_account, query_params)
routing::retrieve_linked_routing_config(
state,
auth.merchant_account,
query_params,
transaction_type,
)
},
#[cfg(not(feature = "release"))]
auth::auth_type(