-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(disputes): add filters for disputes list #5637
Changes from all commits
2a19a2b
aeebef3
530af00
3744ebf
98bfb3c
a31bcb1
7186d81
c6db00e
f05e14c
555741c
d10f28a
6a30270
c7dde68
f1af42f
ea2bcf8
497070d
653ab5a
f6a2d46
314e42a
e4051dc
b6e34e4
4caebd2
37fc8e3
c521cdb
e30dadb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
use std::collections::HashMap; | ||
|
||
use common_utils::types::TimeRange; | ||
use masking::{Deserialize, Serialize}; | ||
use serde::de::Error; | ||
use time::PrimitiveDateTime; | ||
use utoipa::ToSchema; | ||
|
||
use super::enums::{DisputeStage, DisputeStatus}; | ||
use crate::files; | ||
use crate::{admin::MerchantConnectorInfo, enums, files}; | ||
|
||
#[derive(Clone, Debug, Serialize, ToSchema, Eq, PartialEq)] | ||
pub struct DisputeResponse { | ||
|
@@ -108,41 +110,51 @@ pub struct DisputeEvidenceBlock { | |
pub file_metadata_response: files::FileMetadataResponse, | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)] | ||
#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)] | ||
#[serde(deny_unknown_fields)] | ||
pub struct DisputeListConstraints { | ||
/// limit on the number of objects to return | ||
pub limit: Option<i64>, | ||
pub struct DisputeListGetConstraints { | ||
/// The identifier for dispute | ||
pub dispute_id: Option<String>, | ||
/// The payment_id against which dispute is raised | ||
pub payment_id: Option<common_utils::id_type::PaymentId>, | ||
/// Limit on the number of objects to return | ||
pub limit: Option<u32>, | ||
/// The starting point within a list of object | ||
pub offset: Option<u32>, | ||
/// The identifier for business profile | ||
#[schema(value_type = Option<String>)] | ||
pub profile_id: Option<common_utils::id_type::ProfileId>, | ||
/// status of the dispute | ||
pub dispute_status: Option<DisputeStatus>, | ||
/// stage of the dispute | ||
pub dispute_stage: Option<DisputeStage>, | ||
/// reason for the dispute | ||
/// The comma separated list of status of the disputes | ||
#[serde(default, deserialize_with = "parse_comma_separated")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the parse comma thing for backwards compatibility? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes and it will support for open source users too. |
||
pub dispute_status: Option<Vec<DisputeStatus>>, | ||
/// The comma separated list of stages of the disputes | ||
#[serde(default, deserialize_with = "parse_comma_separated")] | ||
pub dispute_stage: Option<Vec<DisputeStage>>, | ||
/// Reason for the dispute | ||
pub reason: Option<String>, | ||
/// connector linked to dispute | ||
pub connector: Option<String>, | ||
/// The time at which dispute is received | ||
#[schema(example = "2022-09-10T10:11:12Z")] | ||
pub received_time: Option<PrimitiveDateTime>, | ||
/// Time less than the dispute received time | ||
#[schema(example = "2022-09-10T10:11:12Z")] | ||
#[serde(rename = "received_time.lt")] | ||
pub received_time_lt: Option<PrimitiveDateTime>, | ||
/// Time greater than the dispute received time | ||
#[schema(example = "2022-09-10T10:11:12Z")] | ||
#[serde(rename = "received_time.gt")] | ||
pub received_time_gt: Option<PrimitiveDateTime>, | ||
/// Time less than or equals to the dispute received time | ||
#[schema(example = "2022-09-10T10:11:12Z")] | ||
#[serde(rename = "received_time.lte")] | ||
pub received_time_lte: Option<PrimitiveDateTime>, | ||
/// Time greater than or equals to the dispute received time | ||
#[schema(example = "2022-09-10T10:11:12Z")] | ||
#[serde(rename = "received_time.gte")] | ||
pub received_time_gte: Option<PrimitiveDateTime>, | ||
/// The comma separated list of connectors linked to disputes | ||
#[serde(default, deserialize_with = "parse_comma_separated")] | ||
pub connector: Option<Vec<String>>, | ||
/// The comma separated list of currencies of the disputes | ||
#[serde(default, deserialize_with = "parse_comma_separated")] | ||
pub currency: Option<Vec<common_enums::Currency>>, | ||
/// The merchant connector id to filter the disputes list | ||
pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>, | ||
/// The time range for which objects are needed. TimeRange has two fields start_time and end_time from which objects can be filtered as per required scenarios (created_at, time less than, greater than etc). | ||
#[serde(flatten)] | ||
pub time_range: Option<TimeRange>, | ||
} | ||
|
||
#[derive(Clone, Debug, serde::Serialize, ToSchema)] | ||
pub struct DisputeListFilters { | ||
/// The map of available connector filters, where the key is the connector name and the value is a list of MerchantConnectorInfo instances | ||
pub connector: HashMap<String, Vec<MerchantConnectorInfo>>, | ||
/// The list of available currency filters | ||
pub currency: Vec<enums::Currency>, | ||
/// The list of available dispute status filters | ||
pub dispute_status: Vec<DisputeStatus>, | ||
/// The list of available dispute stage filters | ||
pub dispute_stage: Vec<DisputeStage>, | ||
} | ||
|
||
#[derive(Default, Clone, Debug, Serialize, Deserialize, ToSchema)] | ||
|
@@ -216,3 +228,19 @@ pub struct DisputesAggregateResponse { | |
/// Different status of disputes with their count | ||
pub status_with_count: HashMap<DisputeStatus, i64>, | ||
} | ||
|
||
fn parse_comma_separated<'de, D, T>(v: D) -> Result<Option<Vec<T>>, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
T: std::str::FromStr, | ||
<T as std::str::FromStr>::Err: std::fmt::Debug + std::fmt::Display + std::error::Error, | ||
{ | ||
let output = Option::<&str>::deserialize(v)?; | ||
output | ||
.map(|s| { | ||
s.split(",") | ||
.map(|x| x.parse::<T>().map_err(D::Error::custom)) | ||
.collect::<Result<_, _>>() | ||
}) | ||
.transpose() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
use crate::errors; | ||
|
||
pub struct DisputeListConstraints { | ||
pub dispute_id: Option<String>, | ||
pub payment_id: Option<common_utils::id_type::PaymentId>, | ||
pub limit: Option<u32>, | ||
pub offset: Option<u32>, | ||
pub profile_id: Option<Vec<common_utils::id_type::ProfileId>>, | ||
pub dispute_status: Option<Vec<common_enums::DisputeStatus>>, | ||
pub dispute_stage: Option<Vec<common_enums::DisputeStage>>, | ||
pub reason: Option<String>, | ||
pub connector: Option<Vec<String>>, | ||
pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>, | ||
pub currency: Option<Vec<common_enums::Currency>>, | ||
pub time_range: Option<common_utils::types::TimeRange>, | ||
} | ||
|
||
impl | ||
TryFrom<( | ||
api_models::disputes::DisputeListGetConstraints, | ||
Option<Vec<common_utils::id_type::ProfileId>>, | ||
)> for DisputeListConstraints | ||
{ | ||
type Error = error_stack::Report<errors::api_error_response::ApiErrorResponse>; | ||
fn try_from( | ||
(value, auth_profile_id_list): ( | ||
api_models::disputes::DisputeListGetConstraints, | ||
Option<Vec<common_utils::id_type::ProfileId>>, | ||
), | ||
) -> Result<Self, Self::Error> { | ||
let api_models::disputes::DisputeListGetConstraints { | ||
dispute_id, | ||
payment_id, | ||
limit, | ||
offset, | ||
profile_id, | ||
dispute_status, | ||
dispute_stage, | ||
reason, | ||
connector, | ||
merchant_connector_id, | ||
currency, | ||
time_range, | ||
} = value; | ||
let profile_id_from_request_body = profile_id; | ||
// Match both the profile ID from the request body and the list of authenticated profile IDs coming from auth layer | ||
let profile_id_list = match (profile_id_from_request_body, auth_profile_id_list) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please explain here with some code comments? |
||
(None, None) => None, | ||
// Case when the request body profile ID is None, but authenticated profile IDs are available, return the auth list | ||
(None, Some(auth_profile_id_list)) => Some(auth_profile_id_list), | ||
// Case when the request body profile ID is provided, but the auth list is None, create a vector with the request body profile ID | ||
(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)) => { | ||
// Check if the profile ID from the request body is present in the authenticated 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 { | ||
// If the profile ID is not valid, return an error indicating access is not available | ||
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 { | ||
dispute_id, | ||
payment_id, | ||
limit, | ||
offset, | ||
profile_id: profile_id_list, | ||
dispute_status, | ||
dispute_stage, | ||
reason, | ||
connector, | ||
merchant_connector_id, | ||
currency, | ||
time_range, | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need
dispute_id
in DisputeListGetConstraints? We can use Dispute retrieve for point query right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its good to have: