Skip to content

Commit

Permalink
Merge branch 'hotfix-2024.09.06.0' into fix-amount-comp
Browse files Browse the repository at this point in the history
  • Loading branch information
likhinbopanna authored Sep 13, 2024
2 parents 20ab89b + 32fd4ee commit bb15d15
Show file tree
Hide file tree
Showing 16 changed files with 298 additions and 76 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to HyperSwitch will be documented here.

- - -

## 2024.09.06.0-hotfix1

### Features

- Enable payment and refund filter at DB query level ([#5839](https://github.com/juspay/hyperswitch/pull/5839)) ([`b75e864`](https://github.com/juspay/hyperswitch/commit/b75e864bdb503d1a86eb729cea7f2b7186de16c3))

- - -

## 2024.09.06.0

### Features
Expand Down
4 changes: 4 additions & 0 deletions crates/diesel_models/src/query/payment_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ impl PaymentAttempt {
payment_method: Option<Vec<enums::PaymentMethod>>,
payment_method_type: Option<Vec<enums::PaymentMethodType>>,
authentication_type: Option<Vec<enums::AuthenticationType>>,
profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
merchant_connector_id: Option<Vec<common_utils::id_type::MerchantConnectorAccountId>>,
) -> StorageResult<i64> {
let mut filter = <Self as HasTable>::table()
Expand All @@ -346,6 +347,9 @@ impl PaymentAttempt {
if let Some(merchant_connector_id) = merchant_connector_id {
filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id))
}
if let Some(profile_id_list) = profile_id_list {
filter = filter.filter(dsl::profile_id.eq_any(profile_id_list))
}
router_env::logger::debug!(query = %debug_query::<Pg, _>(&filter).to_string());

db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
Expand Down
1 change: 1 addition & 0 deletions crates/hyperswitch_domain_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod payment_methods;
pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod refunds;
pub mod router_data;
pub mod router_data_v2;
pub mod router_flow_types;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub trait PaymentAttemptInterface {
payment_method_type: Option<Vec<storage_enums::PaymentMethodType>>,
authentication_type: Option<Vec<storage_enums::AuthenticationType>>,
merchant_connector_id: Option<Vec<id_type::MerchantConnectorAccountId>>,
profile_id_list: Option<Vec<id_type::ProfileId>>,
storage_scheme: storage_enums::MerchantStorageScheme,
) -> error_stack::Result<i64, errors::StorageError>;
}
Expand Down
135 changes: 112 additions & 23 deletions crates/hyperswitch_domain_models/src/payments/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,16 @@ pub enum PaymentIntentFetchConstraints {
List(Box<PaymentIntentListParams>),
}

impl PaymentIntentFetchConstraints {
pub fn get_profile_id_list(&self) -> Option<Vec<id_type::ProfileId>> {
if let Self::List(pi_list_params) = self {
pi_list_params.profile_id.clone()
} else {
None
}
}
}

pub struct PaymentIntentListParams {
pub offset: u32,
pub starting_at: Option<PrimitiveDateTime>,
Expand All @@ -749,7 +759,7 @@ pub struct PaymentIntentListParams {
pub payment_method_type: Option<Vec<storage_enums::PaymentMethodType>>,
pub authentication_type: Option<Vec<storage_enums::AuthenticationType>>,
pub merchant_connector_id: Option<Vec<id_type::MerchantConnectorAccountId>>,
pub profile_id: Option<id_type::ProfileId>,
pub profile_id: Option<Vec<id_type::ProfileId>>,
pub customer_id: Option<id_type::CustomerId>,
pub starting_after_id: Option<id_type::PaymentId>,
pub ending_before_id: Option<id_type::PaymentId>,
Expand All @@ -759,10 +769,21 @@ pub struct PaymentIntentListParams {

impl From<api_models::payments::PaymentListConstraints> for PaymentIntentFetchConstraints {
fn from(value: api_models::payments::PaymentListConstraints) -> Self {
let api_models::payments::PaymentListConstraints {
customer_id,
starting_after,
ending_before,
limit,
created,
created_lt,
created_gt,
created_lte,
created_gte,
} = value;
Self::List(Box::new(PaymentIntentListParams {
offset: 0,
starting_at: value.created_gte.or(value.created_gt).or(value.created),
ending_at: value.created_lte.or(value.created_lt).or(value.created),
starting_at: created_gte.or(created_gt).or(created),
ending_at: created_lte.or(created_lt).or(created),
amount_filter: None,
connector: None,
currency: None,
Expand All @@ -772,10 +793,10 @@ impl From<api_models::payments::PaymentListConstraints> for PaymentIntentFetchCo
authentication_type: None,
merchant_connector_id: None,
profile_id: None,
customer_id: value.customer_id,
starting_after_id: value.starting_after,
ending_before_id: value.ending_before,
limit: Some(std::cmp::min(value.limit, PAYMENTS_LIST_MAX_LIMIT_V1)),
customer_id,
starting_after_id: starting_after,
ending_before_id: ending_before,
limit: Some(std::cmp::min(limit, PAYMENTS_LIST_MAX_LIMIT_V1)),
order: Default::default(),
}))
}
Expand Down Expand Up @@ -807,28 +828,96 @@ impl From<api_models::payments::TimeRange> for PaymentIntentFetchConstraints {

impl From<api_models::payments::PaymentListFilterConstraints> for PaymentIntentFetchConstraints {
fn from(value: api_models::payments::PaymentListFilterConstraints) -> Self {
if let Some(payment_intent_id) = value.payment_id {
let api_models::payments::PaymentListFilterConstraints {
payment_id,
profile_id,
customer_id,
limit,
offset,
amount_filter,
time_range,
connector,
currency,
status,
payment_method,
payment_method_type,
authentication_type,
merchant_connector_id,
order,
} = value;
if let Some(payment_intent_id) = payment_id {
Self::Single { payment_intent_id }
} else {
Self::List(Box::new(PaymentIntentListParams {
offset: value.offset.unwrap_or_default(),
starting_at: value.time_range.map(|t| t.start_time),
ending_at: value.time_range.and_then(|t| t.end_time),
amount_filter: value.amount_filter,
connector: value.connector,
currency: value.currency,
status: value.status,
payment_method: value.payment_method,
payment_method_type: value.payment_method_type,
authentication_type: value.authentication_type,
merchant_connector_id: value.merchant_connector_id,
profile_id: value.profile_id,
customer_id: value.customer_id,
offset: offset.unwrap_or_default(),
starting_at: time_range.map(|t| t.start_time),
ending_at: time_range.and_then(|t| t.end_time),
amount_filter,
connector,
currency,
status,
payment_method,
payment_method_type,
authentication_type,
merchant_connector_id,
profile_id: profile_id.map(|profile_id| vec![profile_id]),
customer_id,
starting_after_id: None,
ending_before_id: None,
limit: Some(std::cmp::min(value.limit, PAYMENTS_LIST_MAX_LIMIT_V2)),
order: value.order,
limit: Some(std::cmp::min(limit, PAYMENTS_LIST_MAX_LIMIT_V2)),
order,
}))
}
}
}

impl<T> TryFrom<(T, Option<Vec<id_type::ProfileId>>)> for PaymentIntentFetchConstraints
where
Self: From<T>,
{
type Error = error_stack::Report<errors::api_error_response::ApiErrorResponse>;
fn try_from(
(constraints, auth_profile_id_list): (T, Option<Vec<id_type::ProfileId>>),
) -> Result<Self, Self::Error> {
let payment_intent_constraints = Self::from(constraints);
if let Self::List(mut pi_list_params) = payment_intent_constraints {
let profile_id_from_request_body = pi_list_params.profile_id;
match (profile_id_from_request_body, auth_profile_id_list) {
(None, None) => pi_list_params.profile_id = None,
(None, Some(auth_profile_id_list)) => {
pi_list_params.profile_id = Some(auth_profile_id_list)
}
(Some(profile_id_from_request_body), None) => {
pi_list_params.profile_id = Some(profile_id_from_request_body)
}
(Some(profile_id_from_request_body), Some(auth_profile_id_list)) => {
let profile_id_from_request_body_is_available_in_auth_profile_id_list =
profile_id_from_request_body
.iter()
.all(|profile_id| auth_profile_id_list.contains(profile_id));

if profile_id_from_request_body_is_available_in_auth_profile_id_list {
pi_list_params.profile_id = Some(profile_id_from_request_body)
} else {
// This scenario is very unlikely to happen
let inaccessible_profile_ids: Vec<_> = profile_id_from_request_body
.iter()
.filter(|profile_id| !auth_profile_id_list.contains(profile_id))
.collect();
return Err(error_stack::Report::new(
errors::api_error_response::ApiErrorResponse::PreconditionFailed {
message: format!(
"Access not available for the given profile_id {:?}",
inaccessible_profile_ids
),
},
));
}
}
}
Ok(Self::List(pi_list_params))
} else {
Ok(payment_intent_constraints)
}
}
}
82 changes: 82 additions & 0 deletions crates/hyperswitch_domain_models/src/refunds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::errors;

pub struct RefundListConstraints {
pub payment_id: Option<common_utils::id_type::PaymentId>,
pub refund_id: Option<String>,
pub profile_id: Option<Vec<common_utils::id_type::ProfileId>>,
pub limit: Option<i64>,
pub offset: Option<i64>,
pub time_range: Option<api_models::payments::TimeRange>,
pub amount_filter: Option<api_models::payments::AmountFilter>,
pub connector: Option<Vec<String>>,
pub merchant_connector_id: Option<Vec<common_utils::id_type::MerchantConnectorAccountId>>,
pub currency: Option<Vec<common_enums::Currency>>,
pub refund_status: Option<Vec<common_enums::RefundStatus>>,
}

impl
TryFrom<(
api_models::refunds::RefundListRequest,
Option<Vec<common_utils::id_type::ProfileId>>,
)> for RefundListConstraints
{
type Error = error_stack::Report<errors::api_error_response::ApiErrorResponse>;

fn try_from(
(value, auth_profile_id_list): (
api_models::refunds::RefundListRequest,
Option<Vec<common_utils::id_type::ProfileId>>,
),
) -> Result<Self, Self::Error> {
let api_models::refunds::RefundListRequest {
connector,
currency,
refund_status,
payment_id,
refund_id,
profile_id,
limit,
offset,
time_range,
amount_filter,
merchant_connector_id,
} = value;
let profile_id_from_request_body = profile_id;
let profile_id_list = match (profile_id_from_request_body, auth_profile_id_list) {
(None, None) => None,
(None, Some(auth_profile_id_list)) => Some(auth_profile_id_list),
(Some(profile_id_from_request_body), None) => Some(vec![profile_id_from_request_body]),
(Some(profile_id_from_request_body), Some(auth_profile_id_list)) => {
let profile_id_from_request_body_is_available_in_auth_profile_id_list =
auth_profile_id_list.contains(&profile_id_from_request_body);

if profile_id_from_request_body_is_available_in_auth_profile_id_list {
Some(vec![profile_id_from_request_body])
} else {
// This scenario is very unlikely to happen
return Err(error_stack::Report::new(
errors::api_error_response::ApiErrorResponse::PreconditionFailed {
message: format!(
"Access not available for the given profile_id {:?}",
profile_id_from_request_body
),
},
));
}
}
};
Ok(Self {
payment_id,
refund_id,
profile_id: profile_id_list,
limit,
offset,
time_range,
amount_filter,
connector,
merchant_connector_id,
currency,
refund_status,
})
}
}
38 changes: 22 additions & 16 deletions crates/router/src/core/payment_methods/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3652,23 +3652,29 @@ pub async fn list_payment_methods(
api_surcharge_decision_configs::MerchantSurchargeConfigs::default()
};

let collect_shipping_details_from_wallets = business_profile
.as_ref()
.and_then(|business_profile| {
business_profile.always_collect_shipping_details_from_wallet_connector
})
.or(business_profile.as_ref().and_then(|business_profile| {
business_profile.collect_shipping_details_from_wallet_connector
}));
let collect_shipping_details_from_wallets =
business_profile.as_ref().and_then(|business_profile| {
if business_profile
.always_collect_shipping_details_from_wallet_connector
.unwrap_or(false)
{
business_profile.always_collect_shipping_details_from_wallet_connector
} else {
business_profile.collect_shipping_details_from_wallet_connector
}
});

let collect_billing_details_from_wallets = business_profile
.as_ref()
.and_then(|business_profile| {
business_profile.always_collect_billing_details_from_wallet_connector
})
.or(business_profile.as_ref().and_then(|business_profile| {
business_profile.collect_billing_details_from_wallet_connector
}));
let collect_billing_details_from_wallets =
business_profile.as_ref().and_then(|business_profile| {
if business_profile
.always_collect_billing_details_from_wallet_connector
.unwrap_or(false)
{
business_profile.always_collect_billing_details_from_wallet_connector
} else {
business_profile.collect_billing_details_from_wallet_connector
}
});

Ok(services::ApplicationResponse::Json(
api::PaymentMethodListResponse {
Expand Down
Loading

0 comments on commit bb15d15

Please sign in to comment.