Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion crates/api_models/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub struct DisputeResponsePaymentsRetrieve {
pub created_at: PrimitiveDateTime,
}

#[derive(Debug, Serialize, strum::Display, Clone)]
#[derive(Debug, Serialize, Deserialize, strum::Display, Clone)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum EvidenceType {
Expand Down Expand Up @@ -196,3 +196,11 @@ pub struct SubmitEvidenceRequest {
/// Any additional evidence statements
pub uncategorized_text: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct DeleteEvidenceRequest {
/// Id of the dispute
pub dispute_id: String,
/// Evidence Type to be deleted
pub evidence_type: EvidenceType,
}
11 changes: 10 additions & 1 deletion crates/api_models/src/events/dispute.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};

use super::{DisputeResponse, DisputeResponsePaymentsRetrieve, SubmitEvidenceRequest};
use super::{
DeleteEvidenceRequest, DisputeResponse, DisputeResponsePaymentsRetrieve, SubmitEvidenceRequest,
};

impl ApiEventMetric for SubmitEvidenceRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Expand All @@ -23,3 +25,10 @@ impl ApiEventMetric for DisputeResponse {
})
}
}
impl ApiEventMetric for DeleteEvidenceRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Dispute {
dispute_id: self.dispute_id.clone(),
})
}
}
40 changes: 40 additions & 0 deletions crates/router/src/core/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,43 @@ pub async fn retrieve_dispute_evidence(
transformers::get_dispute_evidence_vec(&state, merchant_account, dispute_evidence).await?;
Ok(services::ApplicationResponse::Json(dispute_evidence_vec))
}

pub async fn delete_evidence(
state: AppState,
merchant_account: domain::MerchantAccount,
delete_evidence_request: dispute_models::DeleteEvidenceRequest,
) -> RouterResponse<serde_json::Value> {
let dispute_id = delete_evidence_request.dispute_id.clone();
let dispute = state
.store
.find_dispute_by_merchant_id_dispute_id(&merchant_account.merchant_id, &dispute_id)
.await
.to_not_found_response(errors::ApiErrorResponse::DisputeNotFound {
dispute_id: dispute_id.clone(),
})?;
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 updated_dispute_evidence =
transformers::delete_evidence_file(dispute_evidence, delete_evidence_request.evidence_type);
let update_dispute = diesel_models::dispute::DisputeUpdate::EvidenceUpdate {
evidence: utils::Encode::<api::DisputeEvidence>::encode_to_value(&updated_dispute_evidence)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error while encoding dispute evidence")?
.into(),
};
state
.store
.update_dispute(dispute, update_dispute)
.await
.to_not_found_response(errors::ApiErrorResponse::DisputeNotFound {
dispute_id: dispute_id.to_owned(),
})
.attach_printable_lazy(|| {
format!("Unable to update dispute with dispute_id: {dispute_id}")
})?;
Ok(services::ApplicationResponse::StatusOk)
}
48 changes: 48 additions & 0 deletions crates/router/src/core/disputes/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,54 @@ pub async fn get_dispute_evidence_block(
})
}

pub fn delete_evidence_file(
dispute_evidence: DisputeEvidence,
evidence_type: EvidenceType,
) -> DisputeEvidence {
match evidence_type {
EvidenceType::CancellationPolicy => DisputeEvidence {
cancellation_policy: None,
..dispute_evidence
},
EvidenceType::CustomerCommunication => DisputeEvidence {
customer_communication: None,
..dispute_evidence
},
EvidenceType::CustomerSignature => DisputeEvidence {
customer_signature: None,
..dispute_evidence
},
EvidenceType::Receipt => DisputeEvidence {
receipt: None,
..dispute_evidence
},
EvidenceType::RefundPolicy => DisputeEvidence {
refund_policy: None,
..dispute_evidence
},
EvidenceType::ServiceDocumentation => DisputeEvidence {
service_documentation: None,
..dispute_evidence
},
EvidenceType::ShippingDocumentation => DisputeEvidence {
shipping_documentation: None,
..dispute_evidence
},
EvidenceType::InvoiceShowingDistinctTransactions => DisputeEvidence {
invoice_showing_distinct_transactions: None,
..dispute_evidence
},
EvidenceType::RecurringTransactionAgreement => DisputeEvidence {
recurring_transaction_agreement: None,
..dispute_evidence
},
EvidenceType::UncategorizedFile => DisputeEvidence {
uncategorized_file: None,
..dispute_evidence
},
}
}

pub async fn get_dispute_evidence_vec(
state: &AppState,
merchant_account: domain::MerchantAccount,
Expand Down
3 changes: 2 additions & 1 deletion crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,8 @@ impl Disputes {
.service(
web::resource("/evidence")
.route(web::post().to(submit_dispute_evidence))
.route(web::put().to(attach_dispute_evidence)),
.route(web::put().to(attach_dispute_evidence))
.route(web::delete().to(delete_dispute_evidence)),
)
.service(
web::resource("/evidence/{dispute_id}")
Expand Down
38 changes: 38 additions & 0 deletions crates/router/src/routes/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,41 @@ pub async fn retrieve_dispute_evidence(
))
.await
}

/// Disputes - Delete Evidence attached to a Dispute
///
/// To delete an evidence file attached to a dispute
#[utoipa::path(
put,
path = "/disputes/evidence",
request_body=DeleteEvidenceRequest,
responses(
(status = 200, description = "Evidence deleted from a dispute"),
(status = 400, description = "Bad Request")
),
tag = "Disputes",
operation_id = "Delete Evidence attached to a Dispute",
security(("api_key" = []))
)]
#[instrument(skip_all, fields(flow = ?Flow::DeleteDisputeEvidence))]
pub async fn delete_dispute_evidence(
state: web::Data<AppState>,
req: HttpRequest,
json_payload: web::Json<dispute_models::DeleteEvidenceRequest>,
) -> HttpResponse {
let flow = Flow::DeleteDisputeEvidence;
Box::pin(api::server_wrap(
flow,
state,
&req,
json_payload.into_inner(),
|state, auth, req| disputes::delete_evidence(state, auth.merchant_account, req),
auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable,
))
.await
}
3 changes: 2 additions & 1 deletion crates/router/src/routes/lock_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ impl From<Flow> for ApiIdentifier {
| Flow::DisputesList
| Flow::DisputesEvidenceSubmit
| Flow::AttachDisputeEvidence
| Flow::RetrieveDisputeEvidence => Self::Disputes,
| Flow::RetrieveDisputeEvidence
| Flow::DeleteDisputeEvidence => Self::Disputes,

Flow::CardsInfo => Self::CardsInfo,

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 @@ -233,6 +233,8 @@ pub enum Flow {
CreateConfigKey,
/// Attach Dispute Evidence flow
AttachDisputeEvidence,
/// Delete Dispute Evidence flow
DeleteDisputeEvidence,
/// Retrieve Dispute Evidence flow
RetrieveDisputeEvidence,
/// Invalidate cache flow
Expand Down