mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 19:42:27 +08:00
feat(payment_method): API to list countries and currencies supported by a country and payment method type (#4126)
Co-authored-by: Mani Chandra Dulam <mani.dchandra@juspay.in> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -3,8 +3,9 @@ use common_utils::events::{ApiEventMetric, ApiEventsType};
|
||||
use crate::{
|
||||
payment_methods::{
|
||||
CustomerDefaultPaymentMethodResponse, CustomerPaymentMethodsListResponse,
|
||||
DefaultPaymentMethod, PaymentMethodDeleteResponse, PaymentMethodListRequest,
|
||||
PaymentMethodListResponse, PaymentMethodResponse, PaymentMethodUpdate,
|
||||
DefaultPaymentMethod, ListCountriesCurrenciesRequest, ListCountriesCurrenciesResponse,
|
||||
PaymentMethodDeleteResponse, PaymentMethodListRequest, PaymentMethodListResponse,
|
||||
PaymentMethodResponse, PaymentMethodUpdate,
|
||||
},
|
||||
payments::{
|
||||
PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters,
|
||||
@ -131,6 +132,9 @@ impl ApiEventMetric for PaymentMethodListRequest {
|
||||
}
|
||||
}
|
||||
|
||||
impl ApiEventMetric for ListCountriesCurrenciesRequest {}
|
||||
|
||||
impl ApiEventMetric for ListCountriesCurrenciesResponse {}
|
||||
impl ApiEventMetric for PaymentMethodListResponse {}
|
||||
|
||||
impl ApiEventMetric for CustomerDefaultPaymentMethodResponse {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use cards::CardNumber;
|
||||
use common_utils::{
|
||||
@ -914,6 +914,26 @@ pub struct TokenizedCardValue1 {
|
||||
pub card_token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListCountriesCurrenciesRequest {
|
||||
pub connector: api_enums::Connector,
|
||||
pub payment_method_type: api_enums::PaymentMethodType,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListCountriesCurrenciesResponse {
|
||||
pub currencies: HashSet<api_enums::Currency>,
|
||||
pub countries: HashSet<CountryCodeWithName>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Eq, Hash, PartialEq)]
|
||||
pub struct CountryCodeWithName {
|
||||
pub code: api_enums::CountryAlpha2,
|
||||
pub name: api_enums::Country,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TokenizedCardValue2 {
|
||||
|
||||
@ -1626,6 +1626,7 @@ pub enum DisputeStatus {
|
||||
serde::Deserialize,
|
||||
serde::Serialize,
|
||||
strum::Display,
|
||||
strum::EnumIter,
|
||||
strum::EnumString,
|
||||
utoipa::ToSchema,
|
||||
Copy
|
||||
|
||||
@ -7,8 +7,9 @@ use api_models::{
|
||||
admin::{self, PaymentMethodsEnabled},
|
||||
enums::{self as api_enums},
|
||||
payment_methods::{
|
||||
BankAccountTokenData, CardDetailsPaymentMethod, CardNetworkTypes,
|
||||
CustomerDefaultPaymentMethodResponse, MaskedBankDetails, PaymentExperienceTypes,
|
||||
BankAccountTokenData, CardDetailsPaymentMethod, CardNetworkTypes, CountryCodeWithName,
|
||||
CustomerDefaultPaymentMethodResponse, ListCountriesCurrenciesRequest,
|
||||
ListCountriesCurrenciesResponse, MaskedBankDetails, PaymentExperienceTypes,
|
||||
PaymentMethodsData, RequestPaymentMethodTypes, RequiredFieldInfo,
|
||||
ResponsePaymentMethodIntermediate, ResponsePaymentMethodTypes,
|
||||
ResponsePaymentMethodsEnabled,
|
||||
@ -30,6 +31,7 @@ use domain::CustomerUpdate;
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
use masking::Secret;
|
||||
use router_env::{instrument, tracing};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::surcharge_decision_configs::{
|
||||
perform_surcharge_decision_management_for_payment_method_list,
|
||||
@ -3606,3 +3608,59 @@ pub async fn create_encrypted_payment_method_data(
|
||||
|
||||
pm_data_encrypted
|
||||
}
|
||||
|
||||
pub async fn list_countries_currencies_for_connector_payment_method(
|
||||
state: routes::AppState,
|
||||
req: ListCountriesCurrenciesRequest,
|
||||
) -> errors::RouterResponse<ListCountriesCurrenciesResponse> {
|
||||
Ok(services::ApplicationResponse::Json(
|
||||
list_countries_currencies_for_connector_payment_method_util(
|
||||
state.conf.pm_filters.clone(),
|
||||
req.connector,
|
||||
req.payment_method_type,
|
||||
)
|
||||
.await,
|
||||
))
|
||||
}
|
||||
|
||||
// This feature will be more efficient as a WASM function rather than as an API.
|
||||
// So extracting this logic to a separate function so that it can be used in WASM as well.
|
||||
pub async fn list_countries_currencies_for_connector_payment_method_util(
|
||||
connector_filters: settings::ConnectorFilters,
|
||||
connector: api_enums::Connector,
|
||||
payment_method_type: api_enums::PaymentMethodType,
|
||||
) -> ListCountriesCurrenciesResponse {
|
||||
let payment_method_type =
|
||||
settings::PaymentMethodFilterKey::PaymentMethodType(payment_method_type);
|
||||
|
||||
let (currencies, country_codes) = connector_filters
|
||||
.0
|
||||
.get(&connector.to_string())
|
||||
.and_then(|filter| filter.0.get(&payment_method_type))
|
||||
.map(|filter| (filter.currency.clone(), filter.country.clone()))
|
||||
.unwrap_or_else(|| {
|
||||
connector_filters
|
||||
.0
|
||||
.get("default")
|
||||
.and_then(|filter| filter.0.get(&payment_method_type))
|
||||
.map_or((None, None), |filter| {
|
||||
(filter.currency.clone(), filter.country.clone())
|
||||
})
|
||||
});
|
||||
|
||||
let currencies =
|
||||
currencies.unwrap_or_else(|| api_enums::Currency::iter().collect::<HashSet<_>>());
|
||||
let country_codes =
|
||||
country_codes.unwrap_or_else(|| api_enums::CountryAlpha2::iter().collect::<HashSet<_>>());
|
||||
|
||||
ListCountriesCurrenciesResponse {
|
||||
currencies,
|
||||
countries: country_codes
|
||||
.into_iter()
|
||||
.map(|country_code| CountryCodeWithName {
|
||||
code: country_code,
|
||||
name: common_enums::Country::from_alpha2(country_code),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,8 +19,6 @@ use tokio::sync::oneshot;
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
use super::blocklist;
|
||||
#[cfg(any(feature = "olap", feature = "oltp"))]
|
||||
use super::currency;
|
||||
#[cfg(feature = "dummy_connector")]
|
||||
use super::dummy_connector::*;
|
||||
#[cfg(feature = "payouts")]
|
||||
@ -39,8 +37,10 @@ use super::{
|
||||
use super::{cache::*, health::*};
|
||||
#[cfg(any(feature = "olap", feature = "oltp"))]
|
||||
use super::{configs::*, customers::*, mandates::*, payments::*, refunds::*};
|
||||
#[cfg(any(feature = "olap", feature = "oltp"))]
|
||||
use super::{currency, payment_methods::*};
|
||||
#[cfg(feature = "oltp")]
|
||||
use super::{ephemeral_key::*, payment_methods::*, webhooks::*};
|
||||
use super::{ephemeral_key::*, webhooks::*};
|
||||
use crate::configs::secrets_transformers;
|
||||
#[cfg(all(feature = "frm", feature = "oltp"))]
|
||||
use crate::routes::fraud_check as frm_routes;
|
||||
@ -738,11 +738,20 @@ impl Payouts {
|
||||
|
||||
pub struct PaymentMethods;
|
||||
|
||||
#[cfg(feature = "oltp")]
|
||||
#[cfg(any(feature = "olap", feature = "oltp"))]
|
||||
impl PaymentMethods {
|
||||
pub fn server(state: AppState) -> Scope {
|
||||
web::scope("/payment_methods")
|
||||
.app_data(web::Data::new(state))
|
||||
let mut route = web::scope("/payment_methods").app_data(web::Data::new(state));
|
||||
#[cfg(feature = "olap")]
|
||||
{
|
||||
route = route.service(
|
||||
web::resource("/filter")
|
||||
.route(web::get().to(list_countries_currencies_for_connector_payment_method)),
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "oltp")]
|
||||
{
|
||||
route = route
|
||||
.service(
|
||||
web::resource("")
|
||||
.route(web::post().to(create_payment_method_api))
|
||||
@ -754,8 +763,14 @@ impl PaymentMethods {
|
||||
.route(web::post().to(payment_method_update_api))
|
||||
.route(web::delete().to(payment_method_delete_api)),
|
||||
)
|
||||
.service(web::resource("/auth/link").route(web::post().to(pm_auth::link_token_create)))
|
||||
.service(web::resource("/auth/exchange").route(web::post().to(pm_auth::exchange_token)))
|
||||
.service(
|
||||
web::resource("/auth/link").route(web::post().to(pm_auth::link_token_create)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/auth/exchange").route(web::post().to(pm_auth::exchange_token)),
|
||||
)
|
||||
}
|
||||
route
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -97,6 +97,7 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::PaymentMethodsUpdate
|
||||
| Flow::PaymentMethodsDelete
|
||||
| Flow::ValidatePaymentMethod
|
||||
| Flow::ListCountriesCurrencies
|
||||
| Flow::DefaultPaymentMethodsSet => Self::PaymentMethods,
|
||||
|
||||
Flow::PmAuthLinkTokenCreate | Flow::PmAuthExchangeToken => Self::PaymentMethodAuth,
|
||||
|
||||
@ -8,7 +8,7 @@ use time::PrimitiveDateTime;
|
||||
use super::app::AppState;
|
||||
use crate::{
|
||||
core::{api_locking, errors, payment_methods::cards},
|
||||
services::{api, authentication as auth},
|
||||
services::{api, authentication as auth, authorization::permissions::Permission},
|
||||
types::{
|
||||
api::payment_methods::{self, PaymentMethodId},
|
||||
storage::payment_method::PaymentTokenData,
|
||||
@ -262,6 +262,35 @@ pub async fn payment_method_delete_api(
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ListCountriesCurrencies))]
|
||||
pub async fn list_countries_currencies_for_connector_payment_method(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
query_payload: web::Query<payment_methods::ListCountriesCurrenciesRequest>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::ListCountriesCurrencies;
|
||||
let payload = query_payload.into_inner();
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _auth: auth::AuthenticationData, req| {
|
||||
cards::list_countries_currencies_for_connector_payment_method(state, req)
|
||||
},
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::ApiKeyAuth,
|
||||
&auth::JWTAuth(Permission::MerchantConnectorAccountWrite),
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuth(Permission::MerchantConnectorAccountWrite),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::DefaultPaymentMethodsSet))]
|
||||
pub async fn default_payment_method_set_api(
|
||||
state: web::Data<AppState>,
|
||||
@ -297,7 +326,6 @@ pub async fn default_payment_method_set_api(
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
pub use api_models::payment_methods::{
|
||||
CardDetail, CardDetailFromLocker, CardDetailsPaymentMethod, CustomerPaymentMethod,
|
||||
CustomerPaymentMethodsListResponse, DefaultPaymentMethod, DeleteTokenizeByTokenRequest,
|
||||
GetTokenizePayloadRequest, GetTokenizePayloadResponse, PaymentMethodCreate,
|
||||
PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodList, PaymentMethodListRequest,
|
||||
PaymentMethodListResponse, PaymentMethodResponse, PaymentMethodUpdate, PaymentMethodsData,
|
||||
TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2,
|
||||
TokenizedWalletValue1, TokenizedWalletValue2,
|
||||
GetTokenizePayloadRequest, GetTokenizePayloadResponse, ListCountriesCurrenciesRequest,
|
||||
PaymentMethodCreate, PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodList,
|
||||
PaymentMethodListRequest, PaymentMethodListResponse, PaymentMethodResponse,
|
||||
PaymentMethodUpdate, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest,
|
||||
TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
|
||||
};
|
||||
use error_stack::report;
|
||||
|
||||
|
||||
@ -117,6 +117,8 @@ pub enum Flow {
|
||||
CustomerPaymentMethodsList,
|
||||
/// List Customers for a merchant
|
||||
CustomersList,
|
||||
/// Retrieve countries and currencies for connector and payment method
|
||||
ListCountriesCurrencies,
|
||||
/// Payment methods retrieve flow.
|
||||
PaymentMethodsRetrieve,
|
||||
/// Payment methods update flow.
|
||||
|
||||
Reference in New Issue
Block a user