fix(list): adding configuation changes for filtering pm based on countries & currencies (#669)

This commit is contained in:
Nishant Joshi
2023-02-27 17:12:57 +05:30
committed by GitHub
parent b80f19e248
commit 060c54193e
6 changed files with 160 additions and 10 deletions

View File

@ -1,10 +1,14 @@
use std::path::PathBuf;
use std::{
collections::{HashMap, HashSet},
path::PathBuf,
str::FromStr,
};
use common_utils::ext_traits::ConfigExt;
use config::{Environment, File};
use redis_interface::RedisSettings;
pub use router_env::config::{Log, LogConsole, LogFile, LogTelemetry};
use serde::Deserialize;
use serde::{Deserialize, Deserializer};
use crate::{
core::errors::{ApplicationError, ApplicationResult},
@ -51,6 +55,64 @@ pub struct Settings {
pub drainer: DrainerSettings,
pub jwekey: Jwekey,
pub webhooks: WebhooksSettings,
pub pm_filters: ConnectorFilters,
}
#[derive(Debug, Deserialize, Clone, Default)]
#[serde(transparent)]
pub struct ConnectorFilters(pub HashMap<String, PaymentMethodFilters>);
#[derive(Debug, Deserialize, Clone, Default)]
#[serde(transparent)]
pub struct PaymentMethodFilters(
pub HashMap<api_models::enums::PaymentMethodType, CurrencyCountryFilter>,
);
#[derive(Debug, Deserialize, Clone, Default)]
#[serde(default)]
pub struct CurrencyCountryFilter {
#[serde(deserialize_with = "currency_set_deser")]
pub currency: Option<HashSet<api_models::enums::Currency>>,
#[serde(deserialize_with = "string_set_deser")]
pub country: Option<HashSet<String>>,
}
fn string_set_deser<'a, D>(deserializer: D) -> Result<Option<HashSet<String>>, D::Error>
where
D: Deserializer<'a>,
{
let value = <Option<String>>::deserialize(deserializer)?;
Ok(value.and_then(|inner| {
let list = inner
.trim()
.split(',')
.map(|value| value.to_string())
.collect::<HashSet<_>>();
match list.len() {
0 => None,
_ => Some(list),
}
}))
}
fn currency_set_deser<'a, D>(
deserializer: D,
) -> Result<Option<HashSet<api_models::enums::Currency>>, D::Error>
where
D: Deserializer<'a>,
{
let value = <Option<String>>::deserialize(deserializer)?;
Ok(value.and_then(|inner| {
let list = inner
.trim()
.split(',')
.flat_map(api_models::enums::Currency::from_str)
.collect::<HashSet<_>>();
match list.len() {
0 => None,
_ => Some(list),
}
}))
}
#[derive(Debug, Deserialize, Clone)]

View File

@ -14,6 +14,7 @@ use error_stack::{report, ResultExt};
use router_env::{instrument, tracing};
use crate::{
configs::settings,
core::{
errors::{self, StorageErrorExt},
payment_methods::{transformers as payment_methods, vault},
@ -348,10 +349,13 @@ pub async fn delete_card<'a>(
}
pub async fn list_payment_methods(
db: &dyn db::StorageInterface,
state: &routes::AppState,
merchant_account: storage::MerchantAccount,
mut req: api::ListPaymentMethodRequest,
) -> errors::RouterResponse<api::ListPaymentMethodResponse> {
let db = &*state.store;
let pm_config_mapping = &state.conf.pm_filters;
let payment_intent = helpers::verify_client_secret(
db,
merchant_account.storage_scheme,
@ -410,6 +414,7 @@ pub async fn list_payment_methods(
payment_attempt.as_ref(),
address.as_ref(),
mca.connector_name,
pm_config_mapping,
)
.await?;
}
@ -567,6 +572,7 @@ pub async fn list_payment_methods(
)))
}
#[allow(clippy::too_many_arguments)]
async fn filter_payment_methods(
payment_methods: Vec<serde_json::Value>,
req: &mut api::ListPaymentMethodRequest,
@ -575,6 +581,7 @@ async fn filter_payment_methods(
payment_attempt: Option<&storage::PaymentAttempt>,
address: Option<&storage::Address>,
connector: String,
config: &settings::ConnectorFilters,
) -> errors::CustomResult<(), errors::ApiErrorResponse> {
for payment_method in payment_methods.into_iter() {
let parse_result = serde_json::from_value::<PaymentMethodsEnabled>(payment_method);
@ -627,6 +634,16 @@ async fn filter_payment_methods(
true
};
let filter5 = filter_pm_based_on_config(
config,
&connector,
&payment_method_object.payment_method_type,
address.and_then(|inner| inner.country.clone()),
payment_attempt
.and_then(|value| value.currency)
.map(|value| value.foreign_into()),
);
let connector = connector.clone();
let response_pm_type = ResponsePaymentMethodIntermediate::new(
@ -635,7 +652,7 @@ async fn filter_payment_methods(
payment_method,
);
if filter && filter2 && filter3 && filter4 {
if filter && filter2 && filter3 && filter4 && filter5 {
resp.push(response_pm_type);
}
}
@ -645,6 +662,33 @@ async fn filter_payment_methods(
Ok(())
}
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<String>,
currency: Option<api_enums::Currency>,
) -> 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)
})
.unwrap_or(true)
}
fn filter_pm_card_network_based(
pm_card_networks: Option<&Vec<api_enums::CardNetwork>>,
request_card_networks: Option<&Vec<api_enums::CardNetwork>>,

View File

@ -82,9 +82,7 @@ pub async fn list_payment_method_api(
state.get_ref(),
&req,
payload,
|state, merchant_account, req| {
cards::list_payment_methods(&*state.store, merchant_account, req)
},
cards::list_payment_methods,
&*auth,
)
.await