diff --git a/config/config.example.toml b/config/config.example.toml index f5f846dbd6..6a696ed542 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -216,5 +216,5 @@ loop_interval = 500 # Specifies how much time to wait after checking # ^--- This can be any connector (can be multiple) paypal = { currency = "USD,INR", country = "US" } # ^ ^------- comma-separated values -# ^------------------------------- any valid payment method type (can be multiple) +# ^------------------------------- any valid payment method type (can be multiple) (for cards this should be card_network) # If either currency or country isn't provided then, all possible values are accepted diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index 4d7982f8d0..13cfbfdac4 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -34,4 +34,4 @@ router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra [dev-dependencies] fake = "2.5.0" -proptest = "1.0.0" +proptest = "1.1.0" diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index a500b89957..f2903515a4 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -78,9 +78,14 @@ pub struct ConnectorFilters(pub HashMap); #[derive(Debug, Deserialize, Clone, Default)] #[serde(transparent)] -pub struct PaymentMethodFilters( - pub HashMap, -); +pub struct PaymentMethodFilters(pub HashMap); + +#[derive(Debug, Deserialize, Clone, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum PaymentMethodFilterKey { + PaymentMethodType(api_models::enums::PaymentMethodType), + CardNetwork(api_models::enums::CardNetwork), +} #[derive(Debug, Deserialize, Clone, Default)] #[serde(default)] diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 66173a3ab8..b5ca3fff23 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -758,7 +758,8 @@ async fn filter_payment_methods( config, &connector, &payment_method_object.payment_method_type, - address.and_then(|inner| inner.country.clone()), + &mut payment_method_object.card_networks, + &address.and_then(|inner| inner.country.clone()), payment_attempt .and_then(|value| value.currency) .map(|value| value.foreign_into()), @@ -786,29 +787,69 @@ fn filter_pm_based_on_config<'a>( config: &'a crate::configs::settings::ConnectorFilters, connector: &'a str, payment_method_type: &'a api_enums::PaymentMethodType, - country: Option, + card_network: &mut Option>, + country: &Option, currency: Option, ) -> bool { config .0 .get(connector) - .and_then(|inner| inner.0.get(payment_method_type)) - .map(|value| { - let condition1 = value - .country - .as_ref() - .zip(country) - .map(|(lhs, rhs)| lhs.contains(&rhs)); - let condition2 = value - .currency - .as_ref() - .zip(currency) - .map(|(lhs, rhs)| lhs.contains(&rhs)); - condition1.unwrap_or(true) && condition2.unwrap_or(true) + .and_then(|inner| match payment_method_type { + api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => { + card_network_filter(country, currency, card_network, inner); + None + } + payment_method_type => inner + .0 + .get(&settings::PaymentMethodFilterKey::PaymentMethodType( + *payment_method_type, + )) + .map(|value| global_country_currency_filter(value, country, currency)), }) .unwrap_or(true) } +fn card_network_filter( + country: &Option, + currency: Option, + card_network: &mut Option>, + payment_method_filters: &settings::PaymentMethodFilters, +) { + if let Some(value) = card_network.as_mut() { + let filtered_card_networks = value + .iter() + .filter(|&element| { + let key = settings::PaymentMethodFilterKey::CardNetwork(element.clone()); + payment_method_filters + .0 + .get(&key) + .map(|value| global_country_currency_filter(value, country, currency)) + .unwrap_or(true) + }) + .cloned() + .collect::>(); + *value = filtered_card_networks; + } +} + +fn global_country_currency_filter( + item: &settings::CurrencyCountryFilter, + country: &Option, + currency: Option, +) -> bool { + let country_condition = item + .country + .as_ref() + .zip(country.as_ref()) + .map(|(lhs, rhs)| lhs.contains(rhs)); + let currency_condition = item + .currency + .as_ref() + .zip(currency) + .map(|(lhs, rhs)| lhs.contains(&rhs)); + country_condition.unwrap_or(true) && currency_condition.unwrap_or(true) +} + fn filter_pm_card_network_based( pm_card_networks: Option<&Vec>, request_card_networks: Option<&Vec>,