Skip to content

Commit

Permalink
Merge branch 'main' of github.com:juspay/hyperswitch into env_split
Browse files Browse the repository at this point in the history
* 'main' of github.com:juspay/hyperswitch:
  refactor: [Noon] adding new field max_amount to mandate request (#3209)
  fix(events): fix event generation for paymentmethods list (#3337)
  chore(router): remove recon from default features (#3370)
  fix(core): add validation for authtype and metadata in update payment connector (#3305)
  refactor(connector): [cybersource] recurring mandate flow (#3354)
  feat(connector_events): added api to fetch connector event logs (#3319)
  feat(payment_method): add capability to store bank details using /payment_methods endpoint (#3113)
  • Loading branch information
pixincreate committed Jan 17, 2024
2 parents 333d96f + eb2a61d commit 1a23641
Show file tree
Hide file tree
Showing 35 changed files with 827 additions and 333 deletions.
11 changes: 11 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ postman/ @juspay/hyperswitch-framework
Cargo.toml @juspay/hyperswitch-framework
Cargo.lock @juspay/hyperswitch-framework

crates/api_models/src/events/ @juspay/hyperswitch-analytics
crates/api_models/src/events.rs @juspay/hyperswitch-analytics
crates/api_models/src/analytics/ @juspay/hyperswitch-analytics
crates/api_models/src/analytics.rs @juspay/hyperswitch-analytics
crates/router/src/analytics.rs @juspay/hyperswitch-analytics
crates/router/src/events/ @juspay/hyperswitch-analytics
crates/router/src/events.rs @juspay/hyperswitch-analytics
crates/common_utils/src/events/ @juspay/hyperswitch-analytics
crates/common_utils/src/events.rs @juspay/hyperswitch-analytics
crates/analytics/ @juspay/hyperswitch-analytics

connector-template/ @juspay/hyperswitch-connector
crates/router/src/connector/ @juspay/hyperswitch-connector
crates/router/tests/connectors/ @juspay/hyperswitch-connector
Expand Down
16 changes: 16 additions & 0 deletions crates/analytics/src/clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
filters::ApiEventFilter,
metrics::{latency::LatencyAvg, ApiEventMetricRow},
},
connector_events::events::ConnectorEventsResult,
outgoing_webhook_event::events::OutgoingWebhookLogsResult,
sdk_events::events::SdkEventsResult,
types::TableEngine,
Expand Down Expand Up @@ -121,6 +122,7 @@ impl AnalyticsDataSource for ClickhouseClient {
}
AnalyticsCollection::SdkEvents => TableEngine::BasicTree,
AnalyticsCollection::ApiEvents => TableEngine::BasicTree,
AnalyticsCollection::ConnectorEvents => TableEngine::BasicTree,
AnalyticsCollection::OutgoingWebhookEvent => TableEngine::BasicTree,
}
}
Expand All @@ -147,6 +149,7 @@ impl super::sdk_events::events::SdkEventsFilterAnalytics for ClickhouseClient {}
impl super::api_event::events::ApiLogsFilterAnalytics for ClickhouseClient {}
impl super::api_event::filters::ApiEventFilterAnalytics for ClickhouseClient {}
impl super::api_event::metrics::ApiEventMetricAnalytics for ClickhouseClient {}
impl super::connector_events::events::ConnectorEventLogAnalytics for ClickhouseClient {}
impl super::outgoing_webhook_event::events::OutgoingWebhookLogsFilterAnalytics
for ClickhouseClient
{
Expand Down Expand Up @@ -188,6 +191,18 @@ impl TryInto<SdkEventsResult> for serde_json::Value {
}
}

impl TryInto<ConnectorEventsResult> for serde_json::Value {
type Error = Report<ParsingError>;

fn try_into(self) -> Result<ConnectorEventsResult, Self::Error> {
serde_json::from_value(self)
.into_report()
.change_context(ParsingError::StructParseFailure(
"Failed to parse ConnectorEventsResult in clickhouse results",
))
}
}

impl TryInto<PaymentMetricRow> for serde_json::Value {
type Error = Report<ParsingError>;

Expand Down Expand Up @@ -344,6 +359,7 @@ impl ToSql<ClickhouseClient> for AnalyticsCollection {
Self::SdkEvents => Ok("sdk_events_dist".to_string()),
Self::ApiEvents => Ok("api_audit_log".to_string()),
Self::PaymentIntent => Ok("payment_intents_dist".to_string()),
Self::ConnectorEvents => Ok("connector_events_audit".to_string()),
Self::OutgoingWebhookEvent => Ok("outgoing_webhook_events_audit".to_string()),
}
}
Expand Down
5 changes: 5 additions & 0 deletions crates/analytics/src/connector_events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod core;
pub mod events;
pub trait ConnectorEventAnalytics: events::ConnectorEventLogAnalytics {}

pub use self::core::connector_events_core;
27 changes: 27 additions & 0 deletions crates/analytics/src/connector_events/core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use api_models::analytics::connector_events::ConnectorEventsRequest;
use common_utils::errors::ReportSwitchExt;
use error_stack::{IntoReport, ResultExt};

use super::events::{get_connector_events, ConnectorEventsResult};
use crate::{errors::AnalyticsResult, types::FiltersError, AnalyticsProvider};

pub async fn connector_events_core(
pool: &AnalyticsProvider,
req: ConnectorEventsRequest,
merchant_id: String,
) -> AnalyticsResult<Vec<ConnectorEventsResult>> {
let data = match pool {
AnalyticsProvider::Sqlx(_) => Err(FiltersError::NotImplemented(
"Connector Events not implemented for SQLX",
))
.into_report()
.attach_printable("SQL Analytics is not implemented for Connector Events"),
AnalyticsProvider::Clickhouse(ckh_pool)
| AnalyticsProvider::CombinedSqlx(_, ckh_pool)
| AnalyticsProvider::CombinedCkh(_, ckh_pool) => {
get_connector_events(&merchant_id, req, ckh_pool).await
}
}
.switch()?;
Ok(data)
}
63 changes: 63 additions & 0 deletions crates/analytics/src/connector_events/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use api_models::analytics::{
connector_events::{ConnectorEventsRequest, QueryType},
Granularity,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, FiltersError, FiltersResult, LoadRow},
};
pub trait ConnectorEventLogAnalytics: LoadRow<ConnectorEventsResult> {}

pub async fn get_connector_events<T>(
merchant_id: &String,
query_param: ConnectorEventsRequest,
pool: &T,
) -> FiltersResult<Vec<ConnectorEventsResult>>
where
T: AnalyticsDataSource + ConnectorEventLogAnalytics,
PrimitiveDateTime: ToSql<T>,
AnalyticsCollection: ToSql<T>,
Granularity: GroupByClause<T>,
Aggregate<&'static str>: ToSql<T>,
Window<&'static str>: ToSql<T>,
{
let mut query_builder: QueryBuilder<T> =
QueryBuilder::new(AnalyticsCollection::ConnectorEvents);
query_builder.add_select_column("*").switch()?;

query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
match query_param.query_param {
QueryType::Payment { payment_id } => query_builder
.add_filter_clause("payment_id", payment_id)
.switch()?,
}
//TODO!: update the execute_query function to return reports instead of plain errors...
query_builder
.execute_query::<ConnectorEventsResult, _>(pool)
.await
.change_context(FiltersError::QueryBuildingError)?
.change_context(FiltersError::QueryExecutionFailure)
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct ConnectorEventsResult {
pub merchant_id: String,
pub payment_id: String,
pub connector_name: Option<String>,
pub request_id: Option<String>,
pub flow: String,
pub request: String,
pub response: Option<String>,
pub error: Option<String>,
pub status_code: u16,
pub latency: Option<u128>,
#[serde(with = "common_utils::custom_serde::iso8601")]
pub created_at: PrimitiveDateTime,
pub method: Option<String>,
}
1 change: 1 addition & 0 deletions crates/analytics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod query;
pub mod refunds;

pub mod api_event;
pub mod connector_events;
pub mod outgoing_webhook_event;
pub mod sdk_events;
mod sqlx;
Expand Down
2 changes: 2 additions & 0 deletions crates/analytics/src/sqlx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ impl ToSql<SqlxClient> for AnalyticsCollection {
Self::ApiEvents => Err(error_stack::report!(ParsingError::UnknownError)
.attach_printable("ApiEvents table is not implemented for Sqlx"))?,
Self::PaymentIntent => Ok("payment_intent".to_string()),
Self::ConnectorEvents => Err(error_stack::report!(ParsingError::UnknownError)
.attach_printable("ConnectorEvents table is not implemented for Sqlx"))?,
Self::OutgoingWebhookEvent => Err(error_stack::report!(ParsingError::UnknownError)
.attach_printable("OutgoingWebhookEvents table is not implemented for Sqlx"))?,
}
Expand Down
1 change: 1 addition & 0 deletions crates/analytics/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub enum AnalyticsCollection {
SdkEvents,
ApiEvents,
PaymentIntent,
ConnectorEvents,
OutgoingWebhookEvent,
}

Expand Down
2 changes: 1 addition & 1 deletion crates/api_models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ readme = "README.md"
license.workspace = true

[features]
default = ["payouts", "frm", "recon"]
default = ["payouts", "frm"]
business_profile_routing = []
connector_choice_bcompat = []
errors = ["dep:actix-web", "dep:reqwest"]
Expand Down
1 change: 1 addition & 0 deletions crates/api_models/src/analytics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use self::{
pub use crate::payments::TimeRange;

pub mod api_event;
pub mod connector_events;
pub mod outgoing_webhook_event;
pub mod payments;
pub mod refunds;
Expand Down
11 changes: 11 additions & 0 deletions crates/api_models/src/analytics/connector_events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(tag = "type")]
pub enum QueryType {
Payment { payment_id: String },
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct ConnectorEventsRequest {
#[serde(flatten)]
pub query_param: QueryType,
}
6 changes: 4 additions & 2 deletions crates/api_models/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ use common_utils::{
impl_misc_api_event_type,
};

#[allow(unused_imports)]
use crate::{
admin::*,
analytics::{
api_event::*, outgoing_webhook_event::OutgoingWebhookLogsRequest, sdk_events::*, *,
api_event::*, connector_events::ConnectorEventsRequest,
outgoing_webhook_event::OutgoingWebhookLogsRequest, sdk_events::*, *,
},
api_keys::*,
cards_info::*,
Expand All @@ -37,7 +39,6 @@ impl ApiEventMetric for TimeRange {}
impl_misc_api_event_type!(
PaymentMethodId,
PaymentsSessionResponse,
PaymentMethodListResponse,
PaymentMethodCreate,
PaymentLinkInitiateRequest,
RetrievePaymentLinkResponse,
Expand Down Expand Up @@ -94,6 +95,7 @@ impl_misc_api_event_type!(
GetApiEventMetricRequest,
SdkEventsRequest,
ReportRequest,
ConnectorEventsRequest,
OutgoingWebhookLogsRequest
);

Expand Down
4 changes: 3 additions & 1 deletion crates/api_models/src/events/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::{
payment_methods::{
CustomerPaymentMethodsListResponse, PaymentMethodDeleteResponse, PaymentMethodListRequest,
PaymentMethodResponse, PaymentMethodUpdate,
PaymentMethodListResponse, PaymentMethodResponse, PaymentMethodUpdate,
},
payments::{
PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters,
Expand Down Expand Up @@ -119,6 +119,8 @@ impl ApiEventMetric for PaymentMethodListRequest {
}
}

impl ApiEventMetric for PaymentMethodListResponse {}

impl ApiEventMetric for PaymentListFilterConstraints {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
Expand Down
15 changes: 15 additions & 0 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ pub struct PaymentMethodCreate {
/// The card network
#[schema(example = "Visa")]
pub card_network: Option<String>,

/// Payment method details from locker
#[cfg(feature = "payouts")]
#[schema(value_type = Option<Bank>)]
pub bank_transfer: Option<payouts::Bank>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
Expand All @@ -72,6 +77,11 @@ pub struct PaymentMethodUpdate {
#[schema(value_type = Option<CardNetwork>,example = "Visa")]
pub card_network: Option<api_enums::CardNetwork>,

/// Payment method details from locker
#[cfg(feature = "payouts")]
#[schema(value_type = Option<Bank>)]
pub bank_transfer: Option<payouts::Bank>,

/// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
#[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<pii::SecretSerdeValue>,
Expand Down Expand Up @@ -147,6 +157,11 @@ pub struct PaymentMethodResponse {
#[schema(value_type = Option<PrimitiveDateTime>, example = "2023-01-18T11:04:09.922Z")]
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub created: Option<time::PrimitiveDateTime>,

/// Payment method details from locker
#[cfg(feature = "payouts")]
#[schema(value_type = Option<Bank>)]
pub bank_transfer: Option<payouts::Bank>,
}

#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
Expand Down
38 changes: 19 additions & 19 deletions crates/api_models/src/payouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ pub struct Card {

/// The card holder's name
#[schema(value_type = String, example = "John Doe")]
pub card_holder_name: Secret<String>,
pub card_holder_name: Option<Secret<String>>,
}

#[derive(Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
Expand All @@ -195,16 +195,16 @@ pub enum Bank {
#[derive(Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
pub struct AchBankTransfer {
/// Bank name
#[schema(value_type = String, example = "Deutsche Bank")]
pub bank_name: String,
#[schema(value_type = Option<String>, example = "Deutsche Bank")]
pub bank_name: Option<String>,

/// Bank country code
#[schema(value_type = CountryAlpha2, example = "US")]
pub bank_country_code: api_enums::CountryAlpha2,
#[schema(value_type = Option<CountryAlpha2>, example = "US")]
pub bank_country_code: Option<api_enums::CountryAlpha2>,

/// Bank city
#[schema(value_type = String, example = "California")]
pub bank_city: String,
#[schema(value_type = Option<String>, example = "California")]
pub bank_city: Option<String>,

/// Bank account number is an unique identifier assigned by a bank to a customer.
#[schema(value_type = String, example = "000123456")]
Expand All @@ -218,16 +218,16 @@ pub struct AchBankTransfer {
#[derive(Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
pub struct BacsBankTransfer {
/// Bank name
#[schema(value_type = String, example = "Deutsche Bank")]
pub bank_name: String,
#[schema(value_type = Option<String>, example = "Deutsche Bank")]
pub bank_name: Option<String>,

/// Bank country code
#[schema(value_type = CountryAlpha2, example = "US")]
pub bank_country_code: api_enums::CountryAlpha2,
#[schema(value_type = Option<CountryAlpha2>, example = "US")]
pub bank_country_code: Option<api_enums::CountryAlpha2>,

/// Bank city
#[schema(value_type = String, example = "California")]
pub bank_city: String,
#[schema(value_type = Option<String>, example = "California")]
pub bank_city: Option<String>,

/// Bank account number is an unique identifier assigned by a bank to a customer.
#[schema(value_type = String, example = "000123456")]
Expand All @@ -242,16 +242,16 @@ pub struct BacsBankTransfer {
// The SEPA (Single Euro Payments Area) is a pan-European network that allows you to send and receive payments in euros between two cross-border bank accounts in the eurozone.
pub struct SepaBankTransfer {
/// Bank name
#[schema(value_type = String, example = "Deutsche Bank")]
pub bank_name: String,
#[schema(value_type = Option<String>, example = "Deutsche Bank")]
pub bank_name: Option<String>,

/// Bank country code
#[schema(value_type = CountryAlpha2, example = "US")]
pub bank_country_code: api_enums::CountryAlpha2,
#[schema(value_type = Option<CountryAlpha2>, example = "US")]
pub bank_country_code: Option<api_enums::CountryAlpha2>,

/// Bank city
#[schema(value_type = String, example = "California")]
pub bank_city: String,
#[schema(value_type = Option<String>, example = "California")]
pub bank_city: Option<String>,

/// International Bank Account Number (iban) - used in many countries for identifying a bank along with it's customer.
#[schema(value_type = String, example = "DE89370400440532013000")]
Expand Down
Loading

0 comments on commit 1a23641

Please sign in to comment.