Skip to content

Commit

Permalink
feat(router): add retrieve dispute evidence API (#1114)
Browse files Browse the repository at this point in the history
  • Loading branch information
sai-harsha-vardhan authored May 16, 2023
1 parent 9f47f20 commit 354ee01
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 0 deletions.
25 changes: 25 additions & 0 deletions crates/api_models/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use time::PrimitiveDateTime;
use utoipa::ToSchema;

use super::enums::{DisputeStage, DisputeStatus};
use crate::files;

#[derive(Clone, Debug, Serialize, ToSchema, Eq, PartialEq)]
pub struct DisputeResponse {
Expand Down Expand Up @@ -74,6 +75,30 @@ pub struct DisputeResponsePaymentsRetrieve {
pub created_at: PrimitiveDateTime,
}

#[derive(Debug, Serialize, strum::Display, Clone)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum EvidenceType {
CancellationPolicy,
CustomerCommunication,
CustomerSignature,
Receipt,
RefundPolicy,
ServiceDocumentation,
ShippingDocumentation,
InvoiceShowingDistinctTransactions,
RecurringTransactionAgreement,
UncategorizedFile,
}

#[derive(Clone, Debug, Serialize, ToSchema)]
pub struct DisputeEvidenceBlock {
/// Evidence type
pub evidence_type: EvidenceType,
/// File metadata
pub file_metadata_response: files::FileMetadataResponse,
}

#[derive(Clone, Debug, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct DisputeListConstraints {
Expand Down
14 changes: 14 additions & 0 deletions crates/api_models/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,17 @@ pub struct CreateFileResponse {
/// ID of the file created
pub file_id: String,
}

#[derive(Debug, serde::Serialize, ToSchema, Clone)]
pub struct FileMetadataResponse {
/// ID of the file created
pub file_id: String,
/// Name of the file
pub file_name: Option<String>,
/// Size of the file
pub file_size: i32,
/// Type of the file
pub file_type: String,
/// File availability
pub available: bool,
}
24 changes: 24 additions & 0 deletions crates/router/src/core/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,27 @@ pub async fn attach_evidence(
})?;
Ok(create_file_response)
}

#[instrument(skip(state))]
pub async fn retrieve_dispute_evidence(
state: &AppState,
merchant_account: storage::MerchantAccount,
req: disputes::DisputeId,
) -> RouterResponse<Vec<api_models::disputes::DisputeEvidenceBlock>> {
let dispute = state
.store
.find_dispute_by_merchant_id_dispute_id(&merchant_account.merchant_id, &req.dispute_id)
.await
.to_not_found_response(errors::ApiErrorResponse::DisputeNotFound {
dispute_id: req.dispute_id,
})?;
let dispute_evidence: api::DisputeEvidence = dispute
.evidence
.clone()
.parse_value("DisputeEvidence")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error while parsing dispute evidence record")?;
let dispute_evidence_vec =
transformers::get_dispute_evidence_vec(state, merchant_account, dispute_evidence).await?;
Ok(services::ApplicationResponse::Json(dispute_evidence_vec))
}
147 changes: 147 additions & 0 deletions crates/router/src/core/disputes/transformers.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use api_models::disputes::EvidenceType;
use common_utils::errors::CustomResult;
use error_stack::ResultExt;

use crate::{
core::{errors, files::helpers::retrieve_file_and_provider_file_id_from_file_id},
routes::AppState,
types::{
api::{self, DisputeEvidence},
storage,
transformers::ForeignFrom,
SubmitEvidenceRequestData,
},
};
Expand Down Expand Up @@ -186,3 +190,146 @@ pub fn update_dispute_evidence(
},
}
}

pub async fn get_dispute_evidence_block(
state: &AppState,
merchant_account: &storage::MerchantAccount,
evidence_type: EvidenceType,
file_id: String,
) -> CustomResult<api_models::disputes::DisputeEvidenceBlock, errors::ApiErrorResponse> {
let file_metadata = state
.store
.find_file_metadata_by_merchant_id_file_id(&merchant_account.merchant_id, &file_id)
.await
.change_context(errors::ApiErrorResponse::FileNotFound)
.attach_printable("Unable to retrieve file_metadata")?;
let file_metadata_response =
api_models::files::FileMetadataResponse::foreign_from(file_metadata);
Ok(api_models::disputes::DisputeEvidenceBlock {
evidence_type,
file_metadata_response,
})
}

pub async fn get_dispute_evidence_vec(
state: &AppState,
merchant_account: storage::MerchantAccount,
dispute_evidence: DisputeEvidence,
) -> CustomResult<Vec<api_models::disputes::DisputeEvidenceBlock>, errors::ApiErrorResponse> {
let mut dispute_evidence_blocks: Vec<api_models::disputes::DisputeEvidenceBlock> = vec![];
if let Some(cancellation_policy_block) = dispute_evidence.cancellation_policy {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::CancellationPolicy,
cancellation_policy_block,
)
.await?,
)
}
if let Some(customer_communication_block) = dispute_evidence.customer_communication {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::CustomerCommunication,
customer_communication_block,
)
.await?,
)
}
if let Some(customer_signature_block) = dispute_evidence.customer_signature {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::CustomerSignature,
customer_signature_block,
)
.await?,
)
}
if let Some(receipt_block) = dispute_evidence.receipt {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::Receipt,
receipt_block,
)
.await?,
)
}
if let Some(refund_policy_block) = dispute_evidence.refund_policy {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::RefundPolicy,
refund_policy_block,
)
.await?,
)
}
if let Some(service_documentation_block) = dispute_evidence.service_documentation {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::ServiceDocumentation,
service_documentation_block,
)
.await?,
)
}
if let Some(shipping_documentation_block) = dispute_evidence.shipping_documentation {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::ShippingDocumentation,
shipping_documentation_block,
)
.await?,
)
}
if let Some(invoice_showing_distinct_transactions_block) =
dispute_evidence.invoice_showing_distinct_transactions
{
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::InvoiceShowingDistinctTransactions,
invoice_showing_distinct_transactions_block,
)
.await?,
)
}
if let Some(recurring_transaction_agreement_block) =
dispute_evidence.recurring_transaction_agreement
{
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::RecurringTransactionAgreement,
recurring_transaction_agreement_block,
)
.await?,
)
}
if let Some(uncategorized_file_block) = dispute_evidence.uncategorized_file {
dispute_evidence_blocks.push(
get_dispute_evidence_block(
state,
&merchant_account,
EvidenceType::UncategorizedFile,
uncategorized_file_block,
)
.await?,
)
}
Ok(dispute_evidence_blocks)
}
4 changes: 4 additions & 0 deletions crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ impl Disputes {
.route(web::post().to(submit_dispute_evidence))
.route(web::put().to(attach_dispute_evidence)),
)
.service(
web::resource("/evidence/{dispute_id}")
.route(web::get().to(retrieve_dispute_evidence)),
)
.service(web::resource("/{dispute_id}").route(web::get().to(retrieve_dispute)))
}
}
Expand Down
36 changes: 36 additions & 0 deletions crates/router/src/routes/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,39 @@ pub async fn attach_dispute_evidence(
)
.await
}

/// Diputes - Retrieve Dispute
#[utoipa::path(
get,
path = "/disputes/evidence/{dispute_id}",
params(
("dispute_id" = String, Path, description = "The identifier for dispute")
),
responses(
(status = 200, description = "The dispute evidence was retrieved successfully", body = DisputeResponse),
(status = 404, description = "Dispute does not exist in our records")
),
tag = "Disputes",
operation_id = "Retrieve a Dispute Evidence",
security(("api_key" = []))
)]
#[instrument(skip_all, fields(flow = ?Flow::RetrieveDisputeEvidence))]
pub async fn retrieve_dispute_evidence(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<String>,
) -> HttpResponse {
let flow = Flow::RetrieveDisputeEvidence;
let dispute_id = dispute_types::DisputeId {
dispute_id: path.into_inner(),
};
api::server_wrap(
flow,
state.get_ref(),
&req,
dispute_id,
disputes::retrieve_dispute_evidence,
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
)
.await
}
12 changes: 12 additions & 0 deletions crates/router/src/types/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,18 @@ impl ForeignFrom<storage::Dispute> for api_models::disputes::DisputeResponsePaym
}
}

impl ForeignFrom<storage::FileMetadata> for api_models::files::FileMetadataResponse {
fn foreign_from(file_metadata: storage::FileMetadata) -> Self {
Self {
file_id: file_metadata.file_id,
file_name: file_metadata.file_name,
file_size: file_metadata.file_size,
file_type: file_metadata.file_type,
available: file_metadata.available,
}
}
}

impl ForeignFrom<storage_models::cards_info::CardInfo>
for api_models::cards_info::CardInfoResponse
{
Expand Down
2 changes: 2 additions & 0 deletions crates/router_env/src/logger/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ pub enum Flow {
CreateConfigKey,
/// Attach Dispute Evidence flow
AttachDisputeEvidence,
/// Retrieve Dispute Evidence flow
RetrieveDisputeEvidence,
}

///
Expand Down

0 comments on commit 354ee01

Please sign in to comment.