mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +08:00
feat(router): add attach dispute evidence api (#1070)
Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
cc121d0feb
commit
a5756aaecf
@ -1,5 +1,6 @@
|
||||
use api_models::disputes as dispute_models;
|
||||
use error_stack::ResultExt;
|
||||
use api_models::{disputes as dispute_models, files as files_api_models};
|
||||
use common_utils::ext_traits::ValueExt;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use router_env::{instrument, tracing};
|
||||
pub mod transformers;
|
||||
|
||||
@ -8,7 +9,7 @@ use super::{
|
||||
metrics,
|
||||
};
|
||||
use crate::{
|
||||
core::{payments, utils},
|
||||
core::{files, payments, utils as core_utils},
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
@ -18,6 +19,7 @@ use crate::{
|
||||
AcceptDisputeRequestData, AcceptDisputeResponse, DefendDisputeRequestData,
|
||||
DefendDisputeResponse, SubmitEvidenceRequestData, SubmitEvidenceResponse,
|
||||
},
|
||||
utils,
|
||||
};
|
||||
|
||||
#[instrument(skip(state))]
|
||||
@ -111,7 +113,7 @@ pub async fn accept_dispute(
|
||||
AcceptDisputeRequestData,
|
||||
AcceptDisputeResponse,
|
||||
> = connector_data.connector.get_connector_integration();
|
||||
let router_data = utils::construct_accept_dispute_router_data(
|
||||
let router_data = core_utils::construct_accept_dispute_router_data(
|
||||
state,
|
||||
&payment_intent,
|
||||
&payment_attempt,
|
||||
@ -150,7 +152,7 @@ pub async fn accept_dispute(
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable_lazy(|| {
|
||||
format!("Unable to update dispute with dispute_id: {}", dispute_id)
|
||||
format!("Unable to update dispute with dispute_id: {dispute_id}")
|
||||
})?;
|
||||
let dispute_response = api_models::disputes::DisputeResponse::foreign_from(updated_dispute);
|
||||
Ok(services::ApplicationResponse::Json(dispute_response))
|
||||
@ -217,7 +219,7 @@ pub async fn submit_evidence(
|
||||
SubmitEvidenceRequestData,
|
||||
SubmitEvidenceResponse,
|
||||
> = connector_data.connector.get_connector_integration();
|
||||
let router_data = utils::construct_submit_evidence_router_data(
|
||||
let router_data = core_utils::construct_submit_evidence_router_data(
|
||||
state,
|
||||
&payment_intent,
|
||||
&payment_attempt,
|
||||
@ -254,7 +256,7 @@ pub async fn submit_evidence(
|
||||
DefendDisputeRequestData,
|
||||
DefendDisputeResponse,
|
||||
> = connector_data.connector.get_connector_integration();
|
||||
let defend_dispute_router_data = utils::construct_defend_dispute_router_data(
|
||||
let defend_dispute_router_data = core_utils::construct_defend_dispute_router_data(
|
||||
state,
|
||||
&payment_intent,
|
||||
&payment_attempt,
|
||||
@ -299,8 +301,80 @@ pub async fn submit_evidence(
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable_lazy(|| {
|
||||
format!("Unable to update dispute with dispute_id: {}", dispute_id)
|
||||
format!("Unable to update dispute with dispute_id: {dispute_id}")
|
||||
})?;
|
||||
let dispute_response = api_models::disputes::DisputeResponse::foreign_from(updated_dispute);
|
||||
Ok(services::ApplicationResponse::Json(dispute_response))
|
||||
}
|
||||
|
||||
pub async fn attach_evidence(
|
||||
state: &AppState,
|
||||
merchant_account: storage::MerchantAccount,
|
||||
attach_evidence_request: api::AttachEvidenceRequest,
|
||||
) -> RouterResponse<files_api_models::CreateFileResponse> {
|
||||
let db = &state.store;
|
||||
let dispute_id = attach_evidence_request
|
||||
.create_file_request
|
||||
.dispute_id
|
||||
.clone()
|
||||
.ok_or(errors::ApiErrorResponse::MissingDisputeId)?;
|
||||
let dispute = db
|
||||
.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(),
|
||||
})?;
|
||||
common_utils::fp_utils::when(
|
||||
!(dispute.dispute_stage == storage_enums::DisputeStage::Dispute
|
||||
&& dispute.dispute_status == storage_enums::DisputeStatus::DisputeOpened),
|
||||
|| {
|
||||
metrics::ATTACH_EVIDENCE_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC.add(
|
||||
&metrics::CONTEXT,
|
||||
1,
|
||||
&[],
|
||||
);
|
||||
Err(errors::ApiErrorResponse::DisputeStatusValidationFailed {
|
||||
reason: format!(
|
||||
"Evidence cannot be attached because the dispute is in {} stage and has {} status",
|
||||
dispute.dispute_stage, dispute.dispute_status
|
||||
),
|
||||
})
|
||||
},
|
||||
)?;
|
||||
let create_file_response = files::files_create_core(
|
||||
state,
|
||||
merchant_account,
|
||||
attach_evidence_request.create_file_request,
|
||||
)
|
||||
.await?;
|
||||
let file_id = match &create_file_response {
|
||||
services::ApplicationResponse::Json(res) => res.file_id.clone(),
|
||||
_ => Err(errors::ApiErrorResponse::InternalServerError)
|
||||
.into_report()
|
||||
.attach_printable("Unexpected response received from files create core")?,
|
||||
};
|
||||
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::update_dispute_evidence(
|
||||
dispute_evidence,
|
||||
attach_evidence_request.evidence_type,
|
||||
file_id,
|
||||
);
|
||||
let update_dispute = storage_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(),
|
||||
};
|
||||
db.update_dispute(dispute, update_dispute)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable_lazy(|| {
|
||||
format!("Unable to update dispute with dispute_id: {dispute_id}")
|
||||
})?;
|
||||
Ok(create_file_response)
|
||||
}
|
||||
|
||||
@ -3,7 +3,10 @@ use common_utils::errors::CustomResult;
|
||||
use crate::{
|
||||
core::{errors, files::helpers::retrieve_file_and_provider_file_id_from_file_id},
|
||||
routes::AppState,
|
||||
types::{api, SubmitEvidenceRequestData},
|
||||
types::{
|
||||
api::{self, DisputeEvidence},
|
||||
SubmitEvidenceRequestData,
|
||||
},
|
||||
};
|
||||
|
||||
pub async fn get_evidence_request_data(
|
||||
@ -134,3 +137,52 @@ pub async fn get_evidence_request_data(
|
||||
uncategorized_text: evidence_request.uncategorized_text,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update_dispute_evidence(
|
||||
dispute_evidence: DisputeEvidence,
|
||||
evidence_type: api::EvidenceType,
|
||||
file_id: String,
|
||||
) -> DisputeEvidence {
|
||||
match evidence_type {
|
||||
api::EvidenceType::CancellationPolicy => DisputeEvidence {
|
||||
cancellation_policy: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::CustomerCommunication => DisputeEvidence {
|
||||
customer_communication: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::CustomerSignature => DisputeEvidence {
|
||||
customer_signature: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::Receipt => DisputeEvidence {
|
||||
receipt: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::RefundPolicy => DisputeEvidence {
|
||||
refund_policy: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::ServiceDocumentation => DisputeEvidence {
|
||||
service_documentation: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::ShippingDocumentation => DisputeEvidence {
|
||||
shipping_documentation: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::InvoiceShowingDistinctTransactions => DisputeEvidence {
|
||||
invoice_showing_distinct_transactions: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::RecurringTransactionAgreement => DisputeEvidence {
|
||||
recurring_transaction_agreement: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
api::EvidenceType::UncategorizedFile => DisputeEvidence {
|
||||
uncategorized_file: Some(file_id),
|
||||
..dispute_evidence
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,8 +21,13 @@ counter_metric!(
|
||||
counter_metric!(
|
||||
ACCEPT_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC,
|
||||
GLOBAL_METER
|
||||
); //No. of status validation fialures while accpeting a dispute
|
||||
); //No. of status validation failures while accpeting a dispute
|
||||
counter_metric!(
|
||||
EVIDENCE_SUBMISSION_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC,
|
||||
GLOBAL_METER
|
||||
); //No. of status validation fialures while submitting evidence for a dispute
|
||||
); //No. of status validation failures while submitting evidence for a dispute
|
||||
//No. of status validation failures while attaching evidence for a dispute
|
||||
counter_metric!(
|
||||
ATTACH_EVIDENCE_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC,
|
||||
GLOBAL_METER
|
||||
);
|
||||
|
||||
@ -258,6 +258,7 @@ async fn get_or_update_dispute_object(
|
||||
challenge_required_by: dispute_details.challenge_required_by,
|
||||
connector_created_at: dispute_details.created_at,
|
||||
connector_updated_at: dispute_details.updated_at,
|
||||
evidence: None,
|
||||
};
|
||||
state
|
||||
.store
|
||||
|
||||
@ -424,7 +424,11 @@ impl Disputes {
|
||||
.app_data(web::Data::new(state))
|
||||
.service(web::resource("/list").route(web::get().to(retrieve_disputes_list)))
|
||||
.service(web::resource("/accept/{dispute_id}").route(web::post().to(accept_dispute)))
|
||||
.service(web::resource("/evidence").route(web::post().to(submit_dispute_evidence)))
|
||||
.service(
|
||||
web::resource("/evidence")
|
||||
.route(web::post().to(submit_dispute_evidence))
|
||||
.route(web::put().to(attach_dispute_evidence)),
|
||||
)
|
||||
.service(web::resource("/{dispute_id}").route(web::get().to(retrieve_dispute)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
use actix_multipart::Multipart;
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use api_models::disputes as dispute_models;
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
pub mod utils;
|
||||
|
||||
use super::app::AppState;
|
||||
use crate::{
|
||||
core::disputes,
|
||||
services::{api, authentication as auth},
|
||||
types::api::disputes::{self as dispute_types},
|
||||
types::api::disputes as dispute_types,
|
||||
};
|
||||
|
||||
/// Diputes - Retrieve Dispute
|
||||
@ -154,3 +156,42 @@ pub async fn submit_dispute_evidence(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Disputes - Attach Evidence to Dispute
|
||||
///
|
||||
/// To attach an evidence file to dispute
|
||||
#[utoipa::path(
|
||||
put,
|
||||
path = "/disputes/evidence",
|
||||
request_body=MultipartRequestWithFile,
|
||||
responses(
|
||||
(status = 200, description = "Evidence attached to dispute", body = CreateFileResponse),
|
||||
(status = 400, description = "Bad Request")
|
||||
),
|
||||
tag = "Disputes",
|
||||
operation_id = "Attach Evidence to Dispute",
|
||||
security(("api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::AttachDisputeEvidence))]
|
||||
pub async fn attach_dispute_evidence(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
payload: Multipart,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::AttachDisputeEvidence;
|
||||
//Get attach_evidence_request from the multipart request
|
||||
let attach_evidence_request_result = utils::get_attach_evidence_request(payload).await;
|
||||
let attach_evidence_request = match attach_evidence_request_result {
|
||||
Ok(valid_request) => valid_request,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
attach_evidence_request,
|
||||
disputes::attach_evidence,
|
||||
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
102
crates/router/src/routes/disputes/utils.rs
Normal file
102
crates/router/src/routes/disputes/utils.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use actix_multipart::{Field, Multipart};
|
||||
use actix_web::web::Bytes;
|
||||
use common_utils::{errors::CustomResult, ext_traits::StringExt, fp_utils};
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use futures::{StreamExt, TryStreamExt};
|
||||
|
||||
use crate::{
|
||||
core::{errors, files::helpers},
|
||||
types::api::{disputes, files},
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
pub async fn parse_evidence_type(
|
||||
field: &mut Field,
|
||||
) -> CustomResult<Option<disputes::EvidenceType>, errors::ApiErrorResponse> {
|
||||
let purpose = helpers::read_string(field).await;
|
||||
match purpose {
|
||||
Some(evidence_type) => Ok(Some(
|
||||
evidence_type
|
||||
.parse_enum("Evidence Type")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error parsing evidence type")?,
|
||||
)),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_attach_evidence_request(
|
||||
mut payload: Multipart,
|
||||
) -> CustomResult<disputes::AttachEvidenceRequest, errors::ApiErrorResponse> {
|
||||
let mut option_evidence_type: Option<disputes::EvidenceType> = None;
|
||||
let mut dispute_id: Option<String> = None;
|
||||
|
||||
let mut file_name: Option<String> = None;
|
||||
let mut file_content: Option<Vec<Bytes>> = None;
|
||||
|
||||
while let Ok(Some(mut field)) = payload.try_next().await {
|
||||
let content_disposition = field.content_disposition();
|
||||
let field_name = content_disposition.get_name();
|
||||
// Parse the different parameters expected in the multipart request
|
||||
match field_name {
|
||||
Some("file") => {
|
||||
file_name = content_disposition.get_filename().map(String::from);
|
||||
//Collect the file content and throw error if something fails
|
||||
let mut file_data = Vec::new();
|
||||
let mut stream = field.into_stream();
|
||||
while let Some(chunk) = stream.next().await {
|
||||
match chunk {
|
||||
Ok(bytes) => file_data.push(bytes),
|
||||
Err(err) => Err(errors::ApiErrorResponse::InternalServerError)
|
||||
.into_report()
|
||||
.attach_printable_lazy(|| format!("File parsing error: {err}"))?,
|
||||
}
|
||||
}
|
||||
file_content = Some(file_data)
|
||||
}
|
||||
Some("dispute_id") => {
|
||||
dispute_id = helpers::read_string(&mut field).await;
|
||||
}
|
||||
Some("evidence_type") => {
|
||||
option_evidence_type = parse_evidence_type(&mut field).await?;
|
||||
}
|
||||
// Can ignore other params
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let evidence_type = option_evidence_type.get_required_value("evidence_type")?;
|
||||
let file = file_content.get_required_value("file")?.concat().to_vec();
|
||||
//Get and validate file size
|
||||
let file_size: i32 = file
|
||||
.len()
|
||||
.try_into()
|
||||
.into_report()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("File size error")?;
|
||||
// Check if empty file and throw error
|
||||
fp_utils::when(file_size <= 0, || {
|
||||
Err(errors::ApiErrorResponse::MissingFile)
|
||||
.into_report()
|
||||
.attach_printable("Missing / Invalid file in the request")
|
||||
})?;
|
||||
// Get file mime type using 'infer'
|
||||
let kind = infer::get(&file).ok_or(errors::ApiErrorResponse::MissingFileContentType)?;
|
||||
let file_type = kind
|
||||
.mime_type()
|
||||
.parse::<mime::Mime>()
|
||||
.into_report()
|
||||
.change_context(errors::ApiErrorResponse::MissingFileContentType)
|
||||
.attach_printable("File content type error")?;
|
||||
let create_file_request = files::CreateFileRequest {
|
||||
file,
|
||||
file_name,
|
||||
file_size,
|
||||
file_type,
|
||||
purpose: files::FilePurpose::DisputeEvidence,
|
||||
dispute_id,
|
||||
};
|
||||
Ok(disputes::AttachEvidenceRequest {
|
||||
evidence_type,
|
||||
create_file_request,
|
||||
})
|
||||
}
|
||||
@ -22,6 +22,42 @@ pub struct DisputePayload {
|
||||
pub updated_at: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize)]
|
||||
pub struct DisputeEvidence {
|
||||
pub cancellation_policy: Option<String>,
|
||||
pub customer_communication: Option<String>,
|
||||
pub customer_signature: Option<String>,
|
||||
pub receipt: Option<String>,
|
||||
pub refund_policy: Option<String>,
|
||||
pub service_documentation: Option<String>,
|
||||
pub shipping_documentation: Option<String>,
|
||||
pub invoice_showing_distinct_transactions: Option<String>,
|
||||
pub recurring_transaction_agreement: Option<String>,
|
||||
pub uncategorized_file: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AttachEvidenceRequest {
|
||||
pub create_file_request: types::api::CreateFileRequest,
|
||||
pub evidence_type: EvidenceType,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, strum::Display, strum::EnumString, 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(Debug, Clone)]
|
||||
pub struct Accept;
|
||||
|
||||
|
||||
@ -176,6 +176,8 @@ pub enum Flow {
|
||||
RetrieveFile,
|
||||
/// Dispute Evidence submission flow
|
||||
DisputesEvidenceSubmit,
|
||||
/// Attach Dispute Evidence flow
|
||||
AttachDisputeEvidence,
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use common_utils::custom_serde;
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
|
||||
use masking::Secret;
|
||||
use serde::Serialize;
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
@ -25,6 +26,7 @@ pub struct DisputeNew {
|
||||
pub connector_created_at: Option<PrimitiveDateTime>,
|
||||
pub connector_updated_at: Option<PrimitiveDateTime>,
|
||||
pub connector: String,
|
||||
pub evidence: Option<Secret<serde_json::Value>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Identifiable, Queryable)]
|
||||
@ -52,6 +54,7 @@ pub struct Dispute {
|
||||
#[serde(with = "custom_serde::iso8601")]
|
||||
pub modified_at: PrimitiveDateTime,
|
||||
pub connector: String,
|
||||
pub evidence: Secret<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -69,19 +72,23 @@ pub enum DisputeUpdate {
|
||||
dispute_status: storage_enums::DisputeStatus,
|
||||
connector_status: Option<String>,
|
||||
},
|
||||
EvidenceUpdate {
|
||||
evidence: Secret<serde_json::Value>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
|
||||
#[diesel(table_name = dispute)]
|
||||
pub struct DisputeUpdateInternal {
|
||||
dispute_stage: Option<storage_enums::DisputeStage>,
|
||||
dispute_status: storage_enums::DisputeStatus,
|
||||
dispute_status: Option<storage_enums::DisputeStatus>,
|
||||
connector_status: Option<String>,
|
||||
connector_reason: Option<String>,
|
||||
connector_reason_code: Option<String>,
|
||||
challenge_required_by: Option<PrimitiveDateTime>,
|
||||
connector_updated_at: Option<PrimitiveDateTime>,
|
||||
modified_at: Option<PrimitiveDateTime>,
|
||||
evidence: Option<Secret<serde_json::Value>>,
|
||||
}
|
||||
|
||||
impl From<DisputeUpdate> for DisputeUpdateInternal {
|
||||
@ -97,23 +104,28 @@ impl From<DisputeUpdate> for DisputeUpdateInternal {
|
||||
connector_updated_at,
|
||||
} => Self {
|
||||
dispute_stage: Some(dispute_stage),
|
||||
dispute_status,
|
||||
dispute_status: Some(dispute_status),
|
||||
connector_status: Some(connector_status),
|
||||
connector_reason,
|
||||
connector_reason_code,
|
||||
challenge_required_by,
|
||||
connector_updated_at,
|
||||
modified_at: Some(common_utils::date_time::now()),
|
||||
..Default::default()
|
||||
},
|
||||
DisputeUpdate::StatusUpdate {
|
||||
dispute_status,
|
||||
connector_status,
|
||||
} => Self {
|
||||
dispute_status,
|
||||
dispute_status: Some(dispute_status),
|
||||
connector_status,
|
||||
modified_at: Some(common_utils::date_time::now()),
|
||||
..Default::default()
|
||||
},
|
||||
DisputeUpdate::EvidenceUpdate { evidence } => Self {
|
||||
evidence: Some(evidence),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,6 +135,7 @@ diesel::table! {
|
||||
created_at -> Timestamp,
|
||||
modified_at -> Timestamp,
|
||||
connector -> Varchar,
|
||||
evidence -> Jsonb,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
ALTER TABLE dispute DROP COLUMN evidence;
|
||||
@ -0,0 +1,3 @@
|
||||
-- Your SQL goes here
|
||||
ALTER TABLE dispute
|
||||
ADD COLUMN evidence JSONB NOT NULL DEFAULT '{}'::JSONB;
|
||||
Reference in New Issue
Block a user