diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 10a68ef1a4..623abca814 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -518,6 +518,12 @@ pub struct MerchantConnectorWebhookDetails { pub additional_secret: Option>, } +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct MerchantConnectorInfo { + pub connector_label: String, + pub merchant_connector_id: String, +} + /// Response of creating a new Merchant Connector for the merchant account." #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(deny_unknown_fields)] diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs index b26ee0ae68..b27ca142c9 100644 --- a/crates/api_models/src/events/payment.rs +++ b/crates/api_models/src/events/payment.rs @@ -9,8 +9,8 @@ use crate::{ }, payments::{ PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters, - PaymentListResponse, PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelRequest, - PaymentsCaptureRequest, PaymentsExternalAuthenticationRequest, + PaymentListFiltersV2, PaymentListResponse, PaymentListResponseV2, PaymentsApproveRequest, + PaymentsCancelRequest, PaymentsCaptureRequest, PaymentsExternalAuthenticationRequest, PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest, PaymentsRejectRequest, PaymentsRequest, PaymentsResponse, PaymentsRetrieveRequest, PaymentsStartRequest, RedirectionResponse, @@ -158,6 +158,11 @@ impl ApiEventMetric for PaymentListFilters { Some(ApiEventsType::ResourceListAPI) } } +impl ApiEventMetric for PaymentListFiltersV2 { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::ResourceListAPI) + } +} impl ApiEventMetric for PaymentListConstraints { fn get_api_event_type(&self) -> Option { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 7e53e21407..a632933ea0 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1,4 +1,8 @@ -use std::{collections::HashMap, fmt, num::NonZeroI64}; +use std::{ + collections::{HashMap, HashSet}, + fmt, + num::NonZeroI64, +}; use cards::CardNumber; use common_utils::{ @@ -19,8 +23,11 @@ use url::Url; use utoipa::ToSchema; use crate::{ - admin, disputes, enums as api_enums, ephemeral_key::EphemeralKeyCreateResponse, - mandates::RecurringDetails, refunds, + admin::{self, MerchantConnectorInfo}, + disputes, enums as api_enums, + ephemeral_key::EphemeralKeyCreateResponse, + mandates::RecurringDetails, + refunds, }; #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -3419,6 +3426,20 @@ pub struct PaymentListFilters { pub authentication_type: Vec, } +#[derive(Clone, Debug, serde::Serialize)] +pub struct PaymentListFiltersV2 { + /// The list of available connector filters + pub connector: HashMap>, + /// The list of available currency filters + pub currency: Vec, + /// The list of available payment status filters + pub status: Vec, + /// The list payment method and their corresponding types + pub payment_method: HashMap>, + /// The list of available authentication types + pub authentication_type: Vec, +} + #[derive( Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, ToSchema, )] diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index ae8f49c759..9dbe5f4f4b 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1153,6 +1153,7 @@ pub enum MerchantStorageScheme { serde::Deserialize, serde::Serialize, strum::Display, + strum::EnumIter, strum::EnumString, )] #[router_derive::diesel_enum(storage_type = "db_enum")] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 4c087671a2..f0a30fbe66 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -11,8 +11,12 @@ pub mod tokenization; pub mod transformers; pub mod types; +#[cfg(feature = "olap")] +use std::collections::{HashMap, HashSet}; use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant, vec::IntoIter}; +#[cfg(feature = "olap")] +use api_models::admin::MerchantConnectorInfo; use api_models::{ self, enums, mandates::RecurringDetails, @@ -33,6 +37,8 @@ use router_env::{instrument, tracing}; #[cfg(feature = "olap")] use router_types::transformers::ForeignFrom; use scheduler::utils as pt_utils; +#[cfg(feature = "olap")] +use strum::IntoEnumIterator; use time; pub use self::operations::{ @@ -2619,6 +2625,89 @@ pub async fn get_filters_for_payments( )) } +#[cfg(feature = "olap")] +pub async fn get_payment_filters( + state: AppState, + merchant: domain::MerchantAccount, +) -> RouterResponse { + let merchant_connector_accounts = if let services::ApplicationResponse::Json(data) = + super::admin::list_payment_connectors(state, merchant.merchant_id).await? + { + data + } else { + return Err(errors::ApiErrorResponse::InternalServerError.into()); + }; + + let mut connector_map: HashMap> = HashMap::new(); + let mut payment_method_types_map: HashMap< + enums::PaymentMethod, + HashSet, + > = HashMap::new(); + + // populate connector map + merchant_connector_accounts + .iter() + .filter_map(|merchant_connector_account| { + merchant_connector_account + .connector_label + .as_ref() + .map(|label| { + let info = MerchantConnectorInfo { + connector_label: label.clone(), + merchant_connector_id: merchant_connector_account + .merchant_connector_id + .clone(), + }; + (merchant_connector_account.connector_name.clone(), info) + }) + }) + .for_each(|(connector_name, info)| { + connector_map + .entry(connector_name.clone()) + .or_default() + .push(info); + }); + + // populate payment method type map + merchant_connector_accounts + .iter() + .flat_map(|merchant_connector_account| { + merchant_connector_account.payment_methods_enabled.as_ref() + }) + .map(|payment_methods_enabled| { + payment_methods_enabled + .iter() + .filter_map(|payment_method_enabled| { + payment_method_enabled + .payment_method_types + .as_ref() + .map(|types_vec| (payment_method_enabled.payment_method, types_vec.clone())) + }) + }) + .for_each(|payment_methods_enabled| { + payment_methods_enabled.for_each(|(payment_method, payment_method_types_vec)| { + payment_method_types_map + .entry(payment_method) + .or_default() + .extend( + payment_method_types_vec + .iter() + .map(|p| p.payment_method_type), + ); + }); + }); + + Ok(services::ApplicationResponse::Json( + api::PaymentListFiltersV2 { + connector: connector_map, + currency: enums::Currency::iter().collect(), + status: enums::IntentStatus::iter().collect(), + payment_method: payment_method_types_map, + authentication_type: enums::AuthenticationType::iter().collect(), + }, + )) +} + pub async fn add_process_sync_task( db: &dyn StorageInterface, payment_attempt: &storage::PaymentAttempt, diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 74bb8bbc24..3bc68ff79b 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -318,6 +318,7 @@ impl Payments { .route(web::post().to(payments_list_by_filter)), ) .service(web::resource("/filter").route(web::post().to(get_filters_for_payments))) + .service(web::resource("/filter_v2").route(web::get().to(get_payment_filters))) } #[cfg(feature = "oltp")] { diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index 56df8b171c..d9887ac034 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -114,6 +114,7 @@ impl From for ApiIdentifier { | Flow::PaymentsSessionToken | Flow::PaymentsStart | Flow::PaymentsList + | Flow::PaymentsFilters | Flow::PaymentsRedirect | Flow::PaymentsIncrementalAuthorization | Flow::PaymentsExternalAuthentication diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index ac45228f90..c333181778 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -959,6 +959,29 @@ pub async fn get_filters_for_payments( .await } +#[instrument(skip_all, fields(flow = ?Flow::PaymentsFilters))] +#[cfg(feature = "olap")] +pub async fn get_payment_filters( + state: web::Data, + req: actix_web::HttpRequest, +) -> impl Responder { + let flow = Flow::PaymentsFilters; + api::server_wrap( + flow, + state, + &req, + (), + |state, auth, _, _| payments::get_payment_filters(state, auth.merchant_account), + auth::auth_type( + &auth::ApiKeyAuth, + &auth::JWTAuth(Permission::PaymentRead), + req.headers(), + ), + api_locking::LockAction::NotApplicable, + ) + .await +} + #[cfg(feature = "oltp")] #[instrument(skip_all, fields(flow = ?Flow::PaymentsApprove, payment_id))] // #[post("/{payment_id}/approve")] diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index 370e0ca350..4fc3fb4452 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -3,10 +3,10 @@ pub use api_models::payments::{ CryptoData, CustomerAcceptance, HeaderPayload, MandateAmountData, MandateData, MandateTransactionType, MandateType, MandateValidationFields, NextActionType, OnlineMandate, PayLaterData, PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, - PaymentListFilters, PaymentListResponse, PaymentListResponseV2, PaymentMethodData, - PaymentMethodDataRequest, PaymentMethodDataResponse, PaymentOp, PaymentRetrieveBody, - PaymentRetrieveBodyWithCredentials, PaymentsApproveRequest, PaymentsCancelRequest, - PaymentsCaptureRequest, PaymentsExternalAuthenticationRequest, + PaymentListFilters, PaymentListFiltersV2, PaymentListResponse, PaymentListResponseV2, + PaymentMethodData, PaymentMethodDataRequest, PaymentMethodDataResponse, PaymentOp, + PaymentRetrieveBody, PaymentRetrieveBodyWithCredentials, PaymentsApproveRequest, + PaymentsCancelRequest, PaymentsCaptureRequest, PaymentsExternalAuthenticationRequest, PaymentsIncrementalAuthorizationRequest, PaymentsRedirectRequest, PaymentsRedirectionResponse, PaymentsRejectRequest, PaymentsRequest, PaymentsResponse, PaymentsResponseForm, PaymentsRetrieveRequest, PaymentsSessionRequest, PaymentsSessionResponse, PaymentsStartRequest, diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs index 06667f96bb..240bf379f6 100644 --- a/crates/router_env/src/logger/types.rs +++ b/crates/router_env/src/logger/types.rs @@ -151,6 +151,8 @@ pub enum Flow { PaymentsStart, /// Payments list flow. PaymentsList, + // Payments filters flow + PaymentsFilters, #[cfg(feature = "payouts")] /// Payouts create flow PayoutsCreate,