mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat(payment_methods_v2): add total-payment-method-count api (#7479)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -1884,6 +1884,16 @@ pub struct CustomerPaymentMethodsListResponse {
|
|||||||
pub customer_payment_methods: Vec<CustomerPaymentMethod>,
|
pub customer_payment_methods: Vec<CustomerPaymentMethod>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
||||||
|
#[derive(Debug, serde::Serialize, ToSchema)]
|
||||||
|
pub struct TotalPaymentMethodCountResponse {
|
||||||
|
/// total count of payment methods under the merchant
|
||||||
|
pub total_count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
||||||
|
impl common_utils::events::ApiEventMetric for TotalPaymentMethodCountResponse {}
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
any(feature = "v2", feature = "v1"),
|
any(feature = "v2", feature = "v1"),
|
||||||
not(feature = "payment_methods_v2")
|
not(feature = "payment_methods_v2")
|
||||||
|
|||||||
@ -1,23 +1,8 @@
|
|||||||
#[cfg(all(
|
|
||||||
any(feature = "v1", feature = "v2"),
|
|
||||||
not(feature = "payment_methods_v2")
|
|
||||||
))]
|
|
||||||
use async_bb8_diesel::AsyncRunQueryDsl;
|
use async_bb8_diesel::AsyncRunQueryDsl;
|
||||||
#[cfg(all(
|
use diesel::{
|
||||||
any(feature = "v1", feature = "v2"),
|
associations::HasTable, debug_query, pg::Pg, BoolExpressionMethods, ExpressionMethods,
|
||||||
not(feature = "payment_methods_v2")
|
QueryDsl, Table,
|
||||||
))]
|
};
|
||||||
use diesel::Table;
|
|
||||||
use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods};
|
|
||||||
#[cfg(all(
|
|
||||||
any(feature = "v1", feature = "v2"),
|
|
||||||
not(feature = "payment_methods_v2")
|
|
||||||
))]
|
|
||||||
use diesel::{debug_query, pg::Pg, QueryDsl};
|
|
||||||
#[cfg(all(
|
|
||||||
any(feature = "v1", feature = "v2"),
|
|
||||||
not(feature = "payment_methods_v2")
|
|
||||||
))]
|
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
|
|
||||||
use super::generics;
|
use super::generics;
|
||||||
@ -153,6 +138,28 @@ impl PaymentMethod {
|
|||||||
.attach_printable("Failed to get a count of payment methods")
|
.attach_printable("Failed to get a count of payment methods")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_count_by_merchant_id_status(
|
||||||
|
conn: &PgPooledConn,
|
||||||
|
merchant_id: &common_utils::id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> StorageResult<i64> {
|
||||||
|
let query = <Self as HasTable>::table().count().filter(
|
||||||
|
dsl::merchant_id
|
||||||
|
.eq(merchant_id.to_owned())
|
||||||
|
.and(dsl::status.eq(status.to_owned())),
|
||||||
|
);
|
||||||
|
|
||||||
|
router_env::logger::debug!(query = %debug_query::<Pg, _>(&query).to_string());
|
||||||
|
|
||||||
|
generics::db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
|
||||||
|
query.get_result_async::<i64>(conn),
|
||||||
|
generics::db_metrics::DatabaseOperation::Count,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::DatabaseError::Others)
|
||||||
|
.attach_printable("Failed to get a count of payment methods")
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_by_customer_id_merchant_id_status(
|
pub async fn find_by_customer_id_merchant_id_status(
|
||||||
conn: &PgPooledConn,
|
conn: &PgPooledConn,
|
||||||
customer_id: &common_utils::id_type::CustomerId,
|
customer_id: &common_utils::id_type::CustomerId,
|
||||||
@ -275,4 +282,26 @@ impl PaymentMethod {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_count_by_merchant_id_status(
|
||||||
|
conn: &PgPooledConn,
|
||||||
|
merchant_id: &common_utils::id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> StorageResult<i64> {
|
||||||
|
let query = <Self as HasTable>::table().count().filter(
|
||||||
|
dsl::merchant_id
|
||||||
|
.eq(merchant_id.to_owned())
|
||||||
|
.and(dsl::status.eq(status.to_owned())),
|
||||||
|
);
|
||||||
|
|
||||||
|
router_env::logger::debug!(query = %debug_query::<Pg, _>(&query).to_string());
|
||||||
|
|
||||||
|
generics::db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
|
||||||
|
query.get_result_async::<i64>(conn),
|
||||||
|
generics::db_metrics::DatabaseOperation::Count,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::DatabaseError::Others)
|
||||||
|
.attach_printable("Failed to get a count of payment methods")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -786,6 +786,12 @@ pub trait PaymentMethodInterface {
|
|||||||
status: common_enums::PaymentMethodStatus,
|
status: common_enums::PaymentMethodStatus,
|
||||||
) -> CustomResult<i64, errors::StorageError>;
|
) -> CustomResult<i64, errors::StorageError>;
|
||||||
|
|
||||||
|
async fn get_payment_method_count_by_merchant_id_status(
|
||||||
|
&self,
|
||||||
|
merchant_id: &id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> CustomResult<i64, errors::StorageError>;
|
||||||
|
|
||||||
async fn insert_payment_method(
|
async fn insert_payment_method(
|
||||||
&self,
|
&self,
|
||||||
state: &keymanager::KeyManagerState,
|
state: &keymanager::KeyManagerState,
|
||||||
|
|||||||
@ -1308,6 +1308,20 @@ pub async fn list_saved_payment_methods_for_customer(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "v2", feature = "olap"))]
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub async fn get_total_saved_payment_methods_for_merchant(
|
||||||
|
state: SessionState,
|
||||||
|
merchant_account: domain::MerchantAccount,
|
||||||
|
) -> RouterResponse<api::TotalPaymentMethodCountResponse> {
|
||||||
|
let total_payment_method_count =
|
||||||
|
get_total_payment_method_count_core(&state, &merchant_account).await?;
|
||||||
|
|
||||||
|
Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
|
||||||
|
total_payment_method_count,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "v2")]
|
#[cfg(feature = "v2")]
|
||||||
/// Container for the inputs required for the required fields
|
/// Container for the inputs required for the required fields
|
||||||
struct RequiredFieldsInput {
|
struct RequiredFieldsInput {
|
||||||
@ -1778,6 +1792,27 @@ pub async fn list_customer_payment_method_core(
|
|||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "v2", feature = "olap"))]
|
||||||
|
pub async fn get_total_payment_method_count_core(
|
||||||
|
state: &SessionState,
|
||||||
|
merchant_account: &domain::MerchantAccount,
|
||||||
|
) -> RouterResult<api::TotalPaymentMethodCountResponse> {
|
||||||
|
let db = &*state.store;
|
||||||
|
|
||||||
|
let total_count = db
|
||||||
|
.get_payment_method_count_by_merchant_id_status(
|
||||||
|
merchant_account.get_id(),
|
||||||
|
common_enums::PaymentMethodStatus::Active,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Unable to get total payment method count")?;
|
||||||
|
|
||||||
|
let response = api::TotalPaymentMethodCountResponse { total_count };
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn retrieve_payment_method(
|
pub async fn retrieve_payment_method(
|
||||||
|
|||||||
@ -2176,6 +2176,16 @@ impl PaymentMethodInterface for KafkaStore {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_payment_method_count_by_merchant_id_status(
|
||||||
|
&self,
|
||||||
|
merchant_id: &id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> CustomResult<i64, errors::DataStorageError> {
|
||||||
|
self.diesel_store
|
||||||
|
.get_payment_method_count_by_merchant_id_status(merchant_id, status)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
any(feature = "v1", feature = "v2"),
|
any(feature = "v1", feature = "v2"),
|
||||||
not(feature = "payment_methods_v2")
|
not(feature = "payment_methods_v2")
|
||||||
|
|||||||
@ -1039,6 +1039,10 @@ impl Customers {
|
|||||||
{
|
{
|
||||||
route = route
|
route = route
|
||||||
.service(web::resource("/list").route(web::get().to(customers::customers_list)))
|
.service(web::resource("/list").route(web::get().to(customers::customers_list)))
|
||||||
|
.service(
|
||||||
|
web::resource("/total-payment-methods")
|
||||||
|
.route(web::get().to(payment_methods::get_total_payment_method_count)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "oltp", feature = "v2", feature = "customer_v2"))]
|
#[cfg(all(feature = "oltp", feature = "v2", feature = "customer_v2"))]
|
||||||
{
|
{
|
||||||
|
|||||||
@ -118,7 +118,8 @@ impl From<Flow> for ApiIdentifier {
|
|||||||
| Flow::ValidatePaymentMethod
|
| Flow::ValidatePaymentMethod
|
||||||
| Flow::ListCountriesCurrencies
|
| Flow::ListCountriesCurrencies
|
||||||
| Flow::DefaultPaymentMethodsSet
|
| Flow::DefaultPaymentMethodsSet
|
||||||
| Flow::PaymentMethodSave => Self::PaymentMethods,
|
| Flow::PaymentMethodSave
|
||||||
|
| Flow::TotalPaymentMethodCount => Self::PaymentMethods,
|
||||||
|
|
||||||
Flow::PmAuthLinkTokenCreate | Flow::PmAuthExchangeToken => Self::PaymentMethodAuth,
|
Flow::PmAuthLinkTokenCreate | Flow::PmAuthExchangeToken => Self::PaymentMethodAuth,
|
||||||
|
|
||||||
|
|||||||
@ -624,6 +624,37 @@ pub async fn list_customer_payment_method_api(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "v2", feature = "olap"))]
|
||||||
|
#[instrument(skip_all, fields(flow = ?Flow::TotalPaymentMethodCount))]
|
||||||
|
pub async fn get_total_payment_method_count(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> HttpResponse {
|
||||||
|
let flow = Flow::TotalPaymentMethodCount;
|
||||||
|
|
||||||
|
Box::pin(api::server_wrap(
|
||||||
|
flow,
|
||||||
|
state,
|
||||||
|
&req,
|
||||||
|
(),
|
||||||
|
|state, auth: auth::AuthenticationData, _, _| {
|
||||||
|
payment_methods_routes::get_total_saved_payment_methods_for_merchant(
|
||||||
|
state,
|
||||||
|
auth.merchant_account,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
auth::auth_type(
|
||||||
|
&auth::V2ApiKeyAuth,
|
||||||
|
&auth::JWTAuth {
|
||||||
|
permission: Permission::MerchantCustomerRead,
|
||||||
|
},
|
||||||
|
req.headers(),
|
||||||
|
),
|
||||||
|
api_locking::LockAction::NotApplicable,
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
|
||||||
/// Generate a form link for collecting payment methods for a customer
|
/// Generate a form link for collecting payment methods for a customer
|
||||||
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodCollectLink))]
|
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodCollectLink))]
|
||||||
|
|||||||
@ -11,7 +11,7 @@ pub use api_models::payment_methods::{
|
|||||||
PaymentMethodMigrateResponse, PaymentMethodResponse, PaymentMethodResponseData,
|
PaymentMethodMigrateResponse, PaymentMethodResponse, PaymentMethodResponseData,
|
||||||
PaymentMethodUpdate, PaymentMethodUpdateData, PaymentMethodsData, TokenizePayloadEncrypted,
|
PaymentMethodUpdate, PaymentMethodUpdateData, PaymentMethodsData, TokenizePayloadEncrypted,
|
||||||
TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1,
|
TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1,
|
||||||
TokenizedWalletValue2,
|
TokenizedWalletValue2, TotalPaymentMethodCountResponse,
|
||||||
};
|
};
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
any(feature = "v2", feature = "v1"),
|
any(feature = "v2", feature = "v1"),
|
||||||
|
|||||||
@ -574,6 +574,8 @@ pub enum Flow {
|
|||||||
CardsInfoUpdate,
|
CardsInfoUpdate,
|
||||||
/// Cards Info migrate flow
|
/// Cards Info migrate flow
|
||||||
CardsInfoMigrate,
|
CardsInfoMigrate,
|
||||||
|
///Total payment method count for merchant
|
||||||
|
TotalPaymentMethodCount,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for providing generic behaviour to flow metric
|
/// Trait for providing generic behaviour to flow metric
|
||||||
|
|||||||
@ -119,6 +119,17 @@ impl<T: DatabaseStore> PaymentMethodInterface for KVRouterStore<T> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
async fn get_payment_method_count_by_merchant_id_status(
|
||||||
|
&self,
|
||||||
|
merchant_id: &id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> CustomResult<i64, errors::StorageError> {
|
||||||
|
self.router_store
|
||||||
|
.get_payment_method_count_by_merchant_id_status(merchant_id, status)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
async fn insert_payment_method(
|
async fn insert_payment_method(
|
||||||
@ -496,6 +507,21 @@ impl<T: DatabaseStore> PaymentMethodInterface for RouterStore<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
async fn get_payment_method_count_by_merchant_id_status(
|
||||||
|
&self,
|
||||||
|
merchant_id: &id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> CustomResult<i64, errors::StorageError> {
|
||||||
|
let conn = pg_connection_read(self).await?;
|
||||||
|
PaymentMethod::get_count_by_merchant_id_status(&conn, merchant_id, status)
|
||||||
|
.await
|
||||||
|
.map_err(|error| {
|
||||||
|
let new_err = diesel_error_to_data_error(*error.current_context());
|
||||||
|
error.change_context(new_err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
async fn insert_payment_method(
|
async fn insert_payment_method(
|
||||||
&self,
|
&self,
|
||||||
@ -810,6 +836,19 @@ impl PaymentMethodInterface for MockDb {
|
|||||||
i64::try_from(count).change_context(errors::StorageError::MockDbError)
|
i64::try_from(count).change_context(errors::StorageError::MockDbError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_payment_method_count_by_merchant_id_status(
|
||||||
|
&self,
|
||||||
|
merchant_id: &id_type::MerchantId,
|
||||||
|
status: common_enums::PaymentMethodStatus,
|
||||||
|
) -> CustomResult<i64, errors::StorageError> {
|
||||||
|
let payment_methods = self.payment_methods.lock().await;
|
||||||
|
let count = payment_methods
|
||||||
|
.iter()
|
||||||
|
.filter(|pm| pm.merchant_id == *merchant_id && pm.status == status)
|
||||||
|
.count();
|
||||||
|
i64::try_from(count).change_context(errors::StorageError::MockDbError)
|
||||||
|
}
|
||||||
|
|
||||||
async fn insert_payment_method(
|
async fn insert_payment_method(
|
||||||
&self,
|
&self,
|
||||||
_state: &KeyManagerState,
|
_state: &KeyManagerState,
|
||||||
|
|||||||
Reference in New Issue
Block a user