mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 17:47:54 +08:00
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
738 lines
26 KiB
Rust
738 lines
26 KiB
Rust
use std::str::FromStr;
|
|
|
|
use api_models::{
|
|
admin as admin_api, enums as api_enums, payment_methods::RequestPaymentMethodTypes,
|
|
};
|
|
use euclid::{
|
|
dssa::graph::{self, DomainIdentifier},
|
|
frontend::{ast, dir},
|
|
types::{NumValue, NumValueRefinement},
|
|
};
|
|
|
|
use crate::{error::KgraphError, transformers::IntoDirValue};
|
|
|
|
pub const DOMAIN_IDENTIFIER: &str = "payment_methods_enabled_for_merchantconnectoraccount";
|
|
|
|
fn compile_request_pm_types(
|
|
builder: &mut graph::KnowledgeGraphBuilder<'_>,
|
|
pm_types: RequestPaymentMethodTypes,
|
|
pm: api_enums::PaymentMethod,
|
|
) -> Result<graph::NodeId, KgraphError> {
|
|
let mut agg_nodes: Vec<(graph::NodeId, graph::Relation, graph::Strength)> = Vec::new();
|
|
|
|
let pmt_info = "PaymentMethodType";
|
|
let pmt_id = builder
|
|
.make_value_node(
|
|
(pm_types.payment_method_type, pm)
|
|
.into_dir_value()
|
|
.map(Into::into)?,
|
|
Some(pmt_info),
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
None::<()>,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
agg_nodes.push((
|
|
pmt_id,
|
|
graph::Relation::Positive,
|
|
match pm_types.payment_method_type {
|
|
api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => {
|
|
graph::Strength::Weak
|
|
}
|
|
|
|
_ => graph::Strength::Strong,
|
|
},
|
|
));
|
|
|
|
if let Some(card_networks) = pm_types.card_networks {
|
|
if !card_networks.is_empty() {
|
|
let dir_vals: Vec<dir::DirValue> = card_networks
|
|
.into_iter()
|
|
.map(IntoDirValue::into_dir_value)
|
|
.collect::<Result<_, _>>()?;
|
|
|
|
let card_network_info = "Card Networks";
|
|
let card_network_id = builder
|
|
.make_in_aggregator(dir_vals, Some(card_network_info), None::<()>, Vec::new())
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
agg_nodes.push((
|
|
card_network_id,
|
|
graph::Relation::Positive,
|
|
graph::Strength::Weak,
|
|
));
|
|
}
|
|
}
|
|
|
|
let currencies_data = pm_types
|
|
.accepted_currencies
|
|
.and_then(|accepted_currencies| match accepted_currencies {
|
|
admin_api::AcceptedCurrencies::EnableOnly(curr) if !curr.is_empty() => Some((
|
|
curr.into_iter()
|
|
.map(IntoDirValue::into_dir_value)
|
|
.collect::<Result<_, _>>()
|
|
.ok()?,
|
|
graph::Relation::Positive,
|
|
)),
|
|
|
|
admin_api::AcceptedCurrencies::DisableOnly(curr) if !curr.is_empty() => Some((
|
|
curr.into_iter()
|
|
.map(IntoDirValue::into_dir_value)
|
|
.collect::<Result<_, _>>()
|
|
.ok()?,
|
|
graph::Relation::Negative,
|
|
)),
|
|
|
|
_ => None,
|
|
});
|
|
|
|
if let Some((currencies, relation)) = currencies_data {
|
|
let accepted_currencies_info = "Accepted Currencies";
|
|
let accepted_currencies_id = builder
|
|
.make_in_aggregator(
|
|
currencies,
|
|
Some(accepted_currencies_info),
|
|
None::<()>,
|
|
Vec::new(),
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
agg_nodes.push((accepted_currencies_id, relation, graph::Strength::Strong));
|
|
}
|
|
|
|
let mut amount_nodes = Vec::with_capacity(2);
|
|
|
|
if let Some(min_amt) = pm_types.minimum_amount {
|
|
let num_val = NumValue {
|
|
number: min_amt.into(),
|
|
refinement: Some(NumValueRefinement::GreaterThanEqual),
|
|
};
|
|
|
|
let min_amt_info = "Minimum Amount";
|
|
let min_amt_id = builder
|
|
.make_value_node(
|
|
dir::DirValue::PaymentAmount(num_val).into(),
|
|
Some(min_amt_info),
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
None::<()>,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
amount_nodes.push(min_amt_id);
|
|
}
|
|
|
|
if let Some(max_amt) = pm_types.maximum_amount {
|
|
let num_val = NumValue {
|
|
number: max_amt.into(),
|
|
refinement: Some(NumValueRefinement::LessThanEqual),
|
|
};
|
|
|
|
let max_amt_info = "Maximum Amount";
|
|
let max_amt_id = builder
|
|
.make_value_node(
|
|
dir::DirValue::PaymentAmount(num_val).into(),
|
|
Some(max_amt_info),
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
None::<()>,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
amount_nodes.push(max_amt_id);
|
|
}
|
|
|
|
if !amount_nodes.is_empty() {
|
|
let zero_num_val = NumValue {
|
|
number: 0,
|
|
refinement: None,
|
|
};
|
|
|
|
let zero_amt_id = builder
|
|
.make_value_node(
|
|
dir::DirValue::PaymentAmount(zero_num_val).into(),
|
|
Some("zero_amount"),
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
None::<()>,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
let or_node_neighbor_id = if amount_nodes.len() == 1 {
|
|
amount_nodes
|
|
.first()
|
|
.copied()
|
|
.ok_or(KgraphError::IndexingError)?
|
|
} else {
|
|
let nodes = amount_nodes
|
|
.iter()
|
|
.copied()
|
|
.map(|node_id| (node_id, graph::Relation::Positive, graph::Strength::Strong))
|
|
.collect::<Vec<_>>();
|
|
|
|
builder
|
|
.make_all_aggregator(
|
|
&nodes,
|
|
Some("amount_constraint_aggregator"),
|
|
None::<()>,
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?
|
|
};
|
|
|
|
let any_aggregator = builder
|
|
.make_any_aggregator(
|
|
&[
|
|
(zero_amt_id, graph::Relation::Positive),
|
|
(or_node_neighbor_id, graph::Relation::Positive),
|
|
],
|
|
Some("zero_plus_limits_amount_aggregator"),
|
|
None::<()>,
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
agg_nodes.push((
|
|
any_aggregator,
|
|
graph::Relation::Positive,
|
|
graph::Strength::Strong,
|
|
));
|
|
}
|
|
|
|
let pmt_all_aggregator_info = "All Aggregator for PaymentMethodType";
|
|
builder
|
|
.make_all_aggregator(
|
|
&agg_nodes,
|
|
Some(pmt_all_aggregator_info),
|
|
None::<()>,
|
|
Vec::new(),
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)
|
|
}
|
|
|
|
fn compile_payment_method_enabled(
|
|
builder: &mut graph::KnowledgeGraphBuilder<'_>,
|
|
enabled: admin_api::PaymentMethodsEnabled,
|
|
) -> Result<Option<graph::NodeId>, KgraphError> {
|
|
let agg_id = if !enabled
|
|
.payment_method_types
|
|
.as_ref()
|
|
.map(|v| v.is_empty())
|
|
.unwrap_or(true)
|
|
{
|
|
let pm_info = "PaymentMethod";
|
|
let pm_id = builder
|
|
.make_value_node(
|
|
enabled.payment_method.into_dir_value().map(Into::into)?,
|
|
Some(pm_info),
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
None::<()>,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
let mut agg_nodes: Vec<(graph::NodeId, graph::Relation)> = Vec::new();
|
|
|
|
if let Some(pm_types) = enabled.payment_method_types {
|
|
for pm_type in pm_types {
|
|
let node_id = compile_request_pm_types(builder, pm_type, enabled.payment_method)?;
|
|
agg_nodes.push((node_id, graph::Relation::Positive));
|
|
}
|
|
}
|
|
|
|
let any_aggregator_info = "Any aggregation for PaymentMethodsType";
|
|
let pm_type_agg_id = builder
|
|
.make_any_aggregator(
|
|
&agg_nodes,
|
|
Some(any_aggregator_info),
|
|
None::<()>,
|
|
Vec::new(),
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
let all_aggregator_info = "All aggregation for PaymentMethod";
|
|
let enabled_pm_agg_id = builder
|
|
.make_all_aggregator(
|
|
&[
|
|
(pm_id, graph::Relation::Positive, graph::Strength::Strong),
|
|
(
|
|
pm_type_agg_id,
|
|
graph::Relation::Positive,
|
|
graph::Strength::Strong,
|
|
),
|
|
],
|
|
Some(all_aggregator_info),
|
|
None::<()>,
|
|
Vec::new(),
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
Some(enabled_pm_agg_id)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(agg_id)
|
|
}
|
|
|
|
fn compile_merchant_connector_graph(
|
|
builder: &mut graph::KnowledgeGraphBuilder<'_>,
|
|
mca: admin_api::MerchantConnectorResponse,
|
|
) -> Result<(), KgraphError> {
|
|
let connector = common_enums::RoutableConnectors::from_str(&mca.connector_name)
|
|
.map_err(|_| KgraphError::InvalidConnectorName(mca.connector_name.clone()))?;
|
|
|
|
let mut agg_nodes: Vec<(graph::NodeId, graph::Relation)> = Vec::new();
|
|
|
|
if let Some(pms_enabled) = mca.payment_methods_enabled {
|
|
for pm_enabled in pms_enabled {
|
|
let maybe_pm_enabled_id = compile_payment_method_enabled(builder, pm_enabled)?;
|
|
if let Some(pm_enabled_id) = maybe_pm_enabled_id {
|
|
agg_nodes.push((pm_enabled_id, graph::Relation::Positive));
|
|
}
|
|
}
|
|
}
|
|
|
|
let aggregator_info = "Available Payment methods for connector";
|
|
let pms_enabled_agg_id = builder
|
|
.make_any_aggregator(&agg_nodes, Some(aggregator_info), None::<()>, Vec::new())
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
let connector_dir_val = dir::DirValue::Connector(Box::new(ast::ConnectorChoice {
|
|
connector,
|
|
#[cfg(not(feature = "connector_choice_mca_id"))]
|
|
sub_label: mca.business_sub_label,
|
|
}));
|
|
|
|
let connector_info = "Connector";
|
|
let connector_node_id = builder
|
|
.make_value_node(
|
|
connector_dir_val.into(),
|
|
Some(connector_info),
|
|
vec![DomainIdentifier::new(DOMAIN_IDENTIFIER)],
|
|
None::<()>,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
builder
|
|
.make_edge(
|
|
pms_enabled_agg_id,
|
|
connector_node_id,
|
|
graph::Strength::Normal,
|
|
graph::Relation::Positive,
|
|
)
|
|
.map_err(KgraphError::GraphConstructionError)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn make_mca_graph<'a>(
|
|
accts: Vec<admin_api::MerchantConnectorResponse>,
|
|
) -> Result<graph::KnowledgeGraph<'a>, KgraphError> {
|
|
let mut builder = graph::KnowledgeGraphBuilder::new();
|
|
let _domain = builder.make_domain(
|
|
DomainIdentifier::new(DOMAIN_IDENTIFIER),
|
|
"Payment methods enabled for MerchantConnectorAccount".to_string(),
|
|
);
|
|
for acct in accts {
|
|
compile_merchant_connector_graph(&mut builder, acct)?;
|
|
}
|
|
|
|
Ok(builder.build())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#![allow(clippy::expect_used)]
|
|
|
|
use api_models::enums as api_enums;
|
|
use euclid::{
|
|
dirval,
|
|
dssa::graph::{AnalysisContext, Memoization},
|
|
};
|
|
|
|
use super::*;
|
|
|
|
fn build_test_data<'a>() -> graph::KnowledgeGraph<'a> {
|
|
use api_models::{admin::*, payment_methods::*};
|
|
|
|
let stripe_account = MerchantConnectorResponse {
|
|
connector_type: api_enums::ConnectorType::FizOperations,
|
|
connector_name: "stripe".to_string(),
|
|
merchant_connector_id: "something".to_string(),
|
|
business_country: Some(api_enums::CountryAlpha2::US),
|
|
connector_label: Some("something".to_string()),
|
|
business_label: Some("food".to_string()),
|
|
business_sub_label: None,
|
|
connector_account_details: masking::Secret::new(serde_json::json!({})),
|
|
test_mode: None,
|
|
disabled: None,
|
|
metadata: None,
|
|
payment_methods_enabled: Some(vec![PaymentMethodsEnabled {
|
|
payment_method: api_enums::PaymentMethod::Card,
|
|
payment_method_types: Some(vec![
|
|
RequestPaymentMethodTypes {
|
|
payment_method_type: api_enums::PaymentMethodType::Credit,
|
|
payment_experience: None,
|
|
card_networks: Some(vec![
|
|
api_enums::CardNetwork::Visa,
|
|
api_enums::CardNetwork::Mastercard,
|
|
]),
|
|
accepted_currencies: Some(AcceptedCurrencies::EnableOnly(vec![
|
|
api_enums::Currency::USD,
|
|
api_enums::Currency::INR,
|
|
])),
|
|
accepted_countries: None,
|
|
minimum_amount: Some(10),
|
|
maximum_amount: Some(1000),
|
|
recurring_enabled: true,
|
|
installment_payment_enabled: true,
|
|
},
|
|
RequestPaymentMethodTypes {
|
|
payment_method_type: api_enums::PaymentMethodType::Debit,
|
|
payment_experience: None,
|
|
card_networks: Some(vec![
|
|
api_enums::CardNetwork::Maestro,
|
|
api_enums::CardNetwork::JCB,
|
|
]),
|
|
accepted_currencies: Some(AcceptedCurrencies::EnableOnly(vec![
|
|
api_enums::Currency::GBP,
|
|
api_enums::Currency::PHP,
|
|
])),
|
|
accepted_countries: None,
|
|
minimum_amount: Some(10),
|
|
maximum_amount: Some(1000),
|
|
recurring_enabled: true,
|
|
installment_payment_enabled: true,
|
|
},
|
|
]),
|
|
}]),
|
|
frm_configs: None,
|
|
connector_webhook_details: None,
|
|
profile_id: None,
|
|
applepay_verified_domains: None,
|
|
pm_auth_config: None,
|
|
status: api_enums::ConnectorStatus::Inactive,
|
|
};
|
|
|
|
make_mca_graph(vec![stripe_account]).expect("Failed graph construction")
|
|
}
|
|
|
|
#[test]
|
|
fn test_credit_card_success_case() {
|
|
let graph = build_test_data();
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(PaymentMethod = Card),
|
|
dirval!(CardType = Credit),
|
|
dirval!(CardNetwork = Visa),
|
|
dirval!(PaymentCurrency = USD),
|
|
dirval!(PaymentAmount = 100),
|
|
]),
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_debit_card_success_case() {
|
|
let graph = build_test_data();
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(PaymentMethod = Card),
|
|
dirval!(CardType = Debit),
|
|
dirval!(CardNetwork = Maestro),
|
|
dirval!(PaymentCurrency = GBP),
|
|
dirval!(PaymentAmount = 100),
|
|
]),
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_mismatch_failure_case() {
|
|
let graph = build_test_data();
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(PaymentMethod = Card),
|
|
dirval!(CardType = Debit),
|
|
dirval!(CardNetwork = DinersClub),
|
|
dirval!(PaymentCurrency = GBP),
|
|
dirval!(PaymentAmount = 100),
|
|
]),
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_amount_mismatch_failure_case() {
|
|
let graph = build_test_data();
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(PaymentMethod = Card),
|
|
dirval!(CardType = Debit),
|
|
dirval!(CardNetwork = Visa),
|
|
dirval!(PaymentCurrency = GBP),
|
|
dirval!(PaymentAmount = 7),
|
|
]),
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_incomplete_data_failure_case() {
|
|
let graph = build_test_data();
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(PaymentMethod = Card),
|
|
dirval!(CardType = Debit),
|
|
dirval!(PaymentCurrency = GBP),
|
|
dirval!(PaymentAmount = 7),
|
|
]),
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
//println!("{:#?}", result);
|
|
//println!("{}", serde_json::to_string_pretty(&result).expect("Hello"));
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_incomplete_data_failure_case2() {
|
|
let graph = build_test_data();
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(CardType = Debit),
|
|
dirval!(CardNetwork = Visa),
|
|
dirval!(PaymentCurrency = GBP),
|
|
dirval!(PaymentAmount = 100),
|
|
]),
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
//println!("{:#?}", result);
|
|
//println!("{}", serde_json::to_string_pretty(&result).expect("Hello"));
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_sandbox_applepay_bug_usecase() {
|
|
let value = serde_json::json!([
|
|
{
|
|
"connector_type": "payment_processor",
|
|
"connector_name": "bluesnap",
|
|
"merchant_connector_id": "REDACTED",
|
|
"connector_account_details": {
|
|
"auth_type": "BodyKey",
|
|
"api_key": "REDACTED",
|
|
"key1": "REDACTED"
|
|
},
|
|
"test_mode": true,
|
|
"disabled": false,
|
|
"payment_methods_enabled": [
|
|
{
|
|
"payment_method": "card",
|
|
"payment_method_types": [
|
|
{
|
|
"payment_method_type": "credit",
|
|
"payment_experience": null,
|
|
"card_networks": [
|
|
"Mastercard",
|
|
"Visa",
|
|
"AmericanExpress",
|
|
"JCB",
|
|
"DinersClub",
|
|
"Discover",
|
|
"CartesBancaires",
|
|
"UnionPay"
|
|
],
|
|
"accepted_currencies": null,
|
|
"accepted_countries": null,
|
|
"minimum_amount": 1,
|
|
"maximum_amount": 68607706,
|
|
"recurring_enabled": true,
|
|
"installment_payment_enabled": true
|
|
},
|
|
{
|
|
"payment_method_type": "debit",
|
|
"payment_experience": null,
|
|
"card_networks": [
|
|
"Mastercard",
|
|
"Visa",
|
|
"Interac",
|
|
"AmericanExpress",
|
|
"JCB",
|
|
"DinersClub",
|
|
"Discover",
|
|
"CartesBancaires",
|
|
"UnionPay"
|
|
],
|
|
"accepted_currencies": null,
|
|
"accepted_countries": null,
|
|
"minimum_amount": 1,
|
|
"maximum_amount": 68607706,
|
|
"recurring_enabled": true,
|
|
"installment_payment_enabled": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"payment_method": "wallet",
|
|
"payment_method_types": [
|
|
{
|
|
"payment_method_type": "google_pay",
|
|
"payment_experience": "invoke_sdk_client",
|
|
"card_networks": null,
|
|
"accepted_currencies": null,
|
|
"accepted_countries": null,
|
|
"minimum_amount": 1,
|
|
"maximum_amount": 68607706,
|
|
"recurring_enabled": true,
|
|
"installment_payment_enabled": true
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"metadata": {},
|
|
"business_country": "US",
|
|
"business_label": "default",
|
|
"business_sub_label": null,
|
|
"frm_configs": null
|
|
},
|
|
{
|
|
"connector_type": "payment_processor",
|
|
"connector_name": "stripe",
|
|
"merchant_connector_id": "REDACTED",
|
|
"connector_account_details": {
|
|
"auth_type": "HeaderKey",
|
|
"api_key": "REDACTED"
|
|
},
|
|
"test_mode": true,
|
|
"disabled": false,
|
|
"payment_methods_enabled": [
|
|
{
|
|
"payment_method": "card",
|
|
"payment_method_types": [
|
|
{
|
|
"payment_method_type": "credit",
|
|
"payment_experience": null,
|
|
"card_networks": [
|
|
"Mastercard",
|
|
"Visa",
|
|
"AmericanExpress",
|
|
"JCB",
|
|
"DinersClub",
|
|
"Discover",
|
|
"CartesBancaires",
|
|
"UnionPay"
|
|
],
|
|
"accepted_currencies": null,
|
|
"accepted_countries": null,
|
|
"minimum_amount": 1,
|
|
"maximum_amount": 68607706,
|
|
"recurring_enabled": true,
|
|
"installment_payment_enabled": true
|
|
},
|
|
{
|
|
"payment_method_type": "debit",
|
|
"payment_experience": null,
|
|
"card_networks": [
|
|
"Mastercard",
|
|
"Visa",
|
|
"Interac",
|
|
"AmericanExpress",
|
|
"JCB",
|
|
"DinersClub",
|
|
"Discover",
|
|
"CartesBancaires",
|
|
"UnionPay"
|
|
],
|
|
"accepted_currencies": null,
|
|
"accepted_countries": null,
|
|
"minimum_amount": 1,
|
|
"maximum_amount": 68607706,
|
|
"recurring_enabled": true,
|
|
"installment_payment_enabled": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"payment_method": "wallet",
|
|
"payment_method_types": [
|
|
{
|
|
"payment_method_type": "apple_pay",
|
|
"payment_experience": "invoke_sdk_client",
|
|
"card_networks": null,
|
|
"accepted_currencies": null,
|
|
"accepted_countries": null,
|
|
"minimum_amount": 1,
|
|
"maximum_amount": 68607706,
|
|
"recurring_enabled": true,
|
|
"installment_payment_enabled": true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"payment_method": "pay_later",
|
|
"payment_method_types": []
|
|
}
|
|
],
|
|
"metadata": {},
|
|
"business_country": "US",
|
|
"business_label": "default",
|
|
"business_sub_label": null,
|
|
"frm_configs": null
|
|
}
|
|
]);
|
|
|
|
let data: Vec<admin_api::MerchantConnectorResponse> =
|
|
serde_json::from_value(value).expect("data");
|
|
|
|
let graph = make_mca_graph(data).expect("graph");
|
|
let context = AnalysisContext::from_dir_values([
|
|
dirval!(Connector = Stripe),
|
|
dirval!(PaymentAmount = 212),
|
|
dirval!(PaymentCurrency = ILS),
|
|
dirval!(PaymentMethod = Wallet),
|
|
dirval!(WalletType = ApplePay),
|
|
]);
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Stripe),
|
|
&context,
|
|
&mut Memoization::new(),
|
|
);
|
|
|
|
assert!(result.is_ok(), "stripe validation failed");
|
|
|
|
let result = graph.key_value_analysis(
|
|
dirval!(Connector = Bluesnap),
|
|
&context,
|
|
&mut Memoization::new(),
|
|
);
|
|
assert!(result.is_err(), "bluesnap validation failed");
|
|
}
|
|
}
|