mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
feat(connector): add dispute webhooks for Stripe (#918)
This commit is contained in:
@ -31,11 +31,14 @@ pub struct DisputeResponse {
|
||||
/// Reason code of dispute sent by connector
|
||||
pub connector_reason_code: Option<String>,
|
||||
/// Evidence deadline of dispute sent by connector
|
||||
pub challenge_required_by: Option<String>,
|
||||
#[serde(with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub challenge_required_by: Option<PrimitiveDateTime>,
|
||||
/// Dispute created time sent by connector
|
||||
pub created_at: Option<String>,
|
||||
#[serde(with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub created_at: Option<PrimitiveDateTime>,
|
||||
/// Dispute updated time sent by connector
|
||||
pub updated_at: Option<String>,
|
||||
#[serde(with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub updated_at: Option<PrimitiveDateTime>,
|
||||
/// Time at which dispute is received
|
||||
pub received_at: String,
|
||||
}
|
||||
|
||||
@ -880,6 +880,7 @@ impl From<AttemptStatus> for IntentStatus {
|
||||
frunk::LabelledGeneric,
|
||||
ToSchema,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DisputeStage {
|
||||
PreDispute,
|
||||
#[default]
|
||||
@ -901,6 +902,7 @@ pub enum DisputeStage {
|
||||
frunk::LabelledGeneric,
|
||||
ToSchema,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DisputeStatus {
|
||||
#[default]
|
||||
DisputeOpened,
|
||||
|
||||
@ -86,6 +86,74 @@ pub mod iso8601 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Use the UNIX timestamp when serializing and deserializing an
|
||||
/// [`PrimitiveDateTime`][PrimitiveDateTime].
|
||||
///
|
||||
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
||||
pub mod timestamp {
|
||||
|
||||
use serde::{Deserializer, Serialize, Serializer};
|
||||
use time::{serde::timestamp, PrimitiveDateTime, UtcOffset};
|
||||
|
||||
/// Serialize a [`PrimitiveDateTime`] using UNIX timestamp.
|
||||
pub fn serialize<S>(date_time: &PrimitiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
date_time
|
||||
.assume_utc()
|
||||
.unix_timestamp()
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an [`PrimitiveDateTime`] from UNIX timestamp.
|
||||
pub fn deserialize<'a, D>(deserializer: D) -> Result<PrimitiveDateTime, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
timestamp::deserialize(deserializer).map(|offset_date_time| {
|
||||
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
||||
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
||||
})
|
||||
}
|
||||
|
||||
/// Use the UNIX timestamp when serializing and deserializing an
|
||||
/// [`Option<PrimitiveDateTime>`][PrimitiveDateTime].
|
||||
///
|
||||
/// [PrimitiveDateTime]: ::time::PrimitiveDateTime
|
||||
pub mod option {
|
||||
use serde::Serialize;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Serialize an [`Option<PrimitiveDateTime>`] from UNIX timestamp.
|
||||
pub fn serialize<S>(
|
||||
date_time: &Option<PrimitiveDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
date_time
|
||||
.map(|date_time| date_time.assume_utc().unix_timestamp())
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an [`Option<PrimitiveDateTime>`] from UNIX timestamp.
|
||||
pub fn deserialize<'a, D>(deserializer: D) -> Result<Option<PrimitiveDateTime>, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
timestamp::option::deserialize(deserializer).map(|option_offset_date_time| {
|
||||
option_offset_date_time.map(|offset_date_time| {
|
||||
let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC);
|
||||
PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time())
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://github.com/serde-rs/serde/issues/994#issuecomment-316895860>
|
||||
|
||||
pub mod json_string {
|
||||
|
||||
@ -792,7 +792,7 @@ impl api::IncomingWebhook for Adyen {
|
||||
connector_reason_code: notif.additional_data.chargeback_reason_code,
|
||||
challenge_required_by: notif.additional_data.defense_period_ends_at,
|
||||
connector_status: notif.event_code.to_string(),
|
||||
created_at: notif.event_date.clone(),
|
||||
created_at: notif.event_date,
|
||||
updated_at: notif.event_date,
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ use api_models::{enums::DisputeStage, webhooks::IncomingWebhookEvent};
|
||||
use masking::PeekInterface;
|
||||
use reqwest::Url;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{
|
||||
connector::utils::PaymentsAuthorizeRequestData,
|
||||
@ -1553,7 +1554,8 @@ pub struct AdyenAdditionalDataWH {
|
||||
pub hmac_signature: String,
|
||||
pub dispute_status: Option<DisputeStatus>,
|
||||
pub chargeback_reason_code: Option<String>,
|
||||
pub defense_period_ends_at: Option<String>,
|
||||
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub defense_period_ends_at: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@ -1653,7 +1655,8 @@ pub struct AdyenNotificationRequestItemWH {
|
||||
pub merchant_reference: String,
|
||||
pub success: String,
|
||||
pub reason: Option<String>,
|
||||
pub event_date: Option<String>,
|
||||
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub event_date: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
||||
@ -1083,7 +1083,7 @@ impl api::IncomingWebhook for Checkout {
|
||||
.parse_struct("CheckoutWebhookBody")
|
||||
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
|
||||
|
||||
if checkout::is_chargeback_event(&details.txn_type) {
|
||||
if checkout::is_chargeback_event(&details.transaction_type) {
|
||||
return Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
|
||||
api_models::payments::PaymentIdType::ConnectorTransactionId(
|
||||
details
|
||||
@ -1093,7 +1093,7 @@ impl api::IncomingWebhook for Checkout {
|
||||
),
|
||||
));
|
||||
}
|
||||
if checkout::is_refund_event(&details.txn_type) {
|
||||
if checkout::is_refund_event(&details.transaction_type) {
|
||||
return Ok(api_models::webhooks::ObjectReferenceId::RefundId(
|
||||
api_models::webhooks::RefundIdType::ConnectorRefundId(
|
||||
details
|
||||
@ -1117,7 +1117,7 @@ impl api::IncomingWebhook for Checkout {
|
||||
.parse_struct("CheckoutWebhookBody")
|
||||
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
|
||||
|
||||
Ok(api::IncomingWebhookEvent::from(details.txn_type))
|
||||
Ok(api::IncomingWebhookEvent::from(details.transaction_type))
|
||||
}
|
||||
|
||||
fn get_webhook_resource_object(
|
||||
@ -1143,12 +1143,14 @@ impl api::IncomingWebhook for Checkout {
|
||||
Ok(api::disputes::DisputePayload {
|
||||
amount: dispute_details.data.amount.to_string(),
|
||||
currency: dispute_details.data.currency,
|
||||
dispute_stage: api_models::enums::DisputeStage::from(dispute_details.txn_type.clone()),
|
||||
dispute_stage: api_models::enums::DisputeStage::from(
|
||||
dispute_details.transaction_type.clone(),
|
||||
),
|
||||
connector_dispute_id: dispute_details.data.id,
|
||||
connector_reason: None,
|
||||
connector_reason_code: dispute_details.data.reason_code,
|
||||
challenge_required_by: dispute_details.data.evidence_required_by,
|
||||
connector_status: dispute_details.txn_type.to_string(),
|
||||
connector_status: dispute_details.transaction_type.to_string(),
|
||||
created_at: dispute_details.created_on,
|
||||
updated_at: dispute_details.data.date,
|
||||
})
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use common_utils::errors::CustomResult;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
@ -674,27 +675,27 @@ impl From<CheckoutRedirectResponseStatus> for enums::AttemptStatus {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_refund_event(event_code: &CheckoutTxnType) -> bool {
|
||||
pub fn is_refund_event(event_code: &CheckoutTransactionType) -> bool {
|
||||
matches!(
|
||||
event_code,
|
||||
CheckoutTxnType::PaymentRefunded | CheckoutTxnType::PaymentRefundDeclined
|
||||
CheckoutTransactionType::PaymentRefunded | CheckoutTransactionType::PaymentRefundDeclined
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_chargeback_event(event_code: &CheckoutTxnType) -> bool {
|
||||
pub fn is_chargeback_event(event_code: &CheckoutTransactionType) -> bool {
|
||||
matches!(
|
||||
event_code,
|
||||
CheckoutTxnType::DisputeReceived
|
||||
| CheckoutTxnType::DisputeExpired
|
||||
| CheckoutTxnType::DisputeAccepted
|
||||
| CheckoutTxnType::DisputeCanceled
|
||||
| CheckoutTxnType::DisputeEvidenceSubmitted
|
||||
| CheckoutTxnType::DisputeEvidenceAcknowledgedByScheme
|
||||
| CheckoutTxnType::DisputeEvidenceRequired
|
||||
| CheckoutTxnType::DisputeArbitrationLost
|
||||
| CheckoutTxnType::DisputeArbitrationWon
|
||||
| CheckoutTxnType::DisputeWon
|
||||
| CheckoutTxnType::DisputeLost
|
||||
CheckoutTransactionType::DisputeReceived
|
||||
| CheckoutTransactionType::DisputeExpired
|
||||
| CheckoutTransactionType::DisputeAccepted
|
||||
| CheckoutTransactionType::DisputeCanceled
|
||||
| CheckoutTransactionType::DisputeEvidenceSubmitted
|
||||
| CheckoutTransactionType::DisputeEvidenceAcknowledgedByScheme
|
||||
| CheckoutTransactionType::DisputeEvidenceRequired
|
||||
| CheckoutTransactionType::DisputeArbitrationLost
|
||||
| CheckoutTransactionType::DisputeArbitrationWon
|
||||
| CheckoutTransactionType::DisputeWon
|
||||
| CheckoutTransactionType::DisputeLost
|
||||
)
|
||||
}
|
||||
|
||||
@ -705,20 +706,20 @@ pub struct CheckoutWebhookData {
|
||||
pub action_id: Option<String>,
|
||||
pub amount: i32,
|
||||
pub currency: String,
|
||||
pub evidence_required_by: Option<String>,
|
||||
pub evidence_required_by: Option<PrimitiveDateTime>,
|
||||
pub reason_code: Option<String>,
|
||||
pub date: Option<String>,
|
||||
pub date: Option<PrimitiveDateTime>,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CheckoutWebhookBody {
|
||||
#[serde(rename = "type")]
|
||||
pub txn_type: CheckoutTxnType,
|
||||
pub transaction_type: CheckoutTransactionType,
|
||||
pub data: CheckoutWebhookData,
|
||||
pub created_on: Option<String>,
|
||||
pub created_on: Option<PrimitiveDateTime>,
|
||||
}
|
||||
#[derive(Debug, Deserialize, strum::Display, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CheckoutTxnType {
|
||||
pub enum CheckoutTransactionType {
|
||||
PaymentApproved,
|
||||
PaymentDeclined,
|
||||
PaymentRefunded,
|
||||
@ -736,37 +737,35 @@ pub enum CheckoutTxnType {
|
||||
DisputeLost,
|
||||
}
|
||||
|
||||
impl From<CheckoutTxnType> for api::IncomingWebhookEvent {
|
||||
fn from(txn_type: CheckoutTxnType) -> Self {
|
||||
match txn_type {
|
||||
CheckoutTxnType::PaymentApproved => Self::PaymentIntentSuccess,
|
||||
CheckoutTxnType::PaymentDeclined => Self::PaymentIntentSuccess,
|
||||
CheckoutTxnType::PaymentRefunded => Self::RefundSuccess,
|
||||
CheckoutTxnType::PaymentRefundDeclined => Self::RefundFailure,
|
||||
CheckoutTxnType::DisputeReceived | CheckoutTxnType::DisputeEvidenceRequired => {
|
||||
Self::DisputeOpened
|
||||
}
|
||||
CheckoutTxnType::DisputeExpired => Self::DisputeExpired,
|
||||
CheckoutTxnType::DisputeAccepted => Self::DisputeAccepted,
|
||||
CheckoutTxnType::DisputeCanceled => Self::DisputeCancelled,
|
||||
CheckoutTxnType::DisputeEvidenceSubmitted
|
||||
| CheckoutTxnType::DisputeEvidenceAcknowledgedByScheme => Self::DisputeChallenged,
|
||||
CheckoutTxnType::DisputeWon | CheckoutTxnType::DisputeArbitrationWon => {
|
||||
Self::DisputeWon
|
||||
}
|
||||
CheckoutTxnType::DisputeLost | CheckoutTxnType::DisputeArbitrationLost => {
|
||||
Self::DisputeLost
|
||||
impl From<CheckoutTransactionType> for api::IncomingWebhookEvent {
|
||||
fn from(transaction_type: CheckoutTransactionType) -> Self {
|
||||
match transaction_type {
|
||||
CheckoutTransactionType::PaymentApproved => Self::PaymentIntentSuccess,
|
||||
CheckoutTransactionType::PaymentDeclined => Self::PaymentIntentSuccess,
|
||||
CheckoutTransactionType::PaymentRefunded => Self::RefundSuccess,
|
||||
CheckoutTransactionType::PaymentRefundDeclined => Self::RefundFailure,
|
||||
CheckoutTransactionType::DisputeReceived
|
||||
| CheckoutTransactionType::DisputeEvidenceRequired => Self::DisputeOpened,
|
||||
CheckoutTransactionType::DisputeExpired => Self::DisputeExpired,
|
||||
CheckoutTransactionType::DisputeAccepted => Self::DisputeAccepted,
|
||||
CheckoutTransactionType::DisputeCanceled => Self::DisputeCancelled,
|
||||
CheckoutTransactionType::DisputeEvidenceSubmitted
|
||||
| CheckoutTransactionType::DisputeEvidenceAcknowledgedByScheme => {
|
||||
Self::DisputeChallenged
|
||||
}
|
||||
CheckoutTransactionType::DisputeWon
|
||||
| CheckoutTransactionType::DisputeArbitrationWon => Self::DisputeWon,
|
||||
CheckoutTransactionType::DisputeLost
|
||||
| CheckoutTransactionType::DisputeArbitrationLost => Self::DisputeLost,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CheckoutTxnType> for api_models::enums::DisputeStage {
|
||||
fn from(code: CheckoutTxnType) -> Self {
|
||||
impl From<CheckoutTransactionType> for api_models::enums::DisputeStage {
|
||||
fn from(code: CheckoutTransactionType) -> Self {
|
||||
match code {
|
||||
CheckoutTxnType::DisputeArbitrationLost | CheckoutTxnType::DisputeArbitrationWon => {
|
||||
Self::PreArbitration
|
||||
}
|
||||
CheckoutTransactionType::DisputeArbitrationLost
|
||||
| CheckoutTransactionType::DisputeArbitrationWon => Self::PreArbitration,
|
||||
_ => Self::Dispute,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1284,28 +1284,58 @@ impl api::IncomingWebhook for Stripe {
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
|
||||
let details: stripe::StripeWebhookObjectId = request
|
||||
let details: stripe::WebhookEvent = request
|
||||
.body
|
||||
.parse_struct("StripeWebhookObjectId")
|
||||
.parse_struct("WebhookEvent")
|
||||
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
|
||||
|
||||
Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
|
||||
api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.object.id),
|
||||
))
|
||||
Ok(match details.event_data.event_object.object {
|
||||
stripe::WebhookEventObjectType::PaymentIntent => {
|
||||
api_models::webhooks::ObjectReferenceId::PaymentId(
|
||||
api_models::payments::PaymentIdType::ConnectorTransactionId(
|
||||
details.event_data.event_object.id,
|
||||
),
|
||||
)
|
||||
}
|
||||
stripe::WebhookEventObjectType::Dispute => {
|
||||
api_models::webhooks::ObjectReferenceId::PaymentId(
|
||||
api_models::payments::PaymentIdType::ConnectorTransactionId(
|
||||
details
|
||||
.event_data
|
||||
.event_object
|
||||
.payment_intent
|
||||
.ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
|
||||
),
|
||||
)
|
||||
}
|
||||
_ => Err(errors::ConnectorError::WebhookReferenceIdNotFound)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_webhook_event_type(
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
|
||||
let details: stripe::StripeWebhookObjectEventType = request
|
||||
let details: stripe::WebhookEvent = request
|
||||
.body
|
||||
.parse_struct("StripeWebhookObjectEventType")
|
||||
.change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
|
||||
|
||||
Ok(match details.event_type.as_str() {
|
||||
"payment_intent.payment_failed" => api::IncomingWebhookEvent::PaymentIntentFailure,
|
||||
"payment_intent.succeeded" => api::IncomingWebhookEvent::PaymentIntentSuccess,
|
||||
.parse_struct("WebhookEvent")
|
||||
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
|
||||
Ok(match details.event_type {
|
||||
stripe::WebhookEventType::PaymentIntentFailed => {
|
||||
api::IncomingWebhookEvent::PaymentIntentFailure
|
||||
}
|
||||
stripe::WebhookEventType::PaymentIntentSucceed => {
|
||||
api::IncomingWebhookEvent::PaymentIntentSuccess
|
||||
}
|
||||
stripe::WebhookEventType::DisputeCreated => api::IncomingWebhookEvent::DisputeOpened,
|
||||
stripe::WebhookEventType::DisputeClosed => api::IncomingWebhookEvent::DisputeCancelled,
|
||||
stripe::WebhookEventType::DisputeUpdated => api::IncomingWebhookEvent::try_from(
|
||||
details
|
||||
.event_data
|
||||
.event_object
|
||||
.status
|
||||
.ok_or(errors::ConnectorError::WebhookEventTypeNotFound)?,
|
||||
)?,
|
||||
_ => Err(errors::ConnectorError::WebhookEventTypeNotFound).into_report()?,
|
||||
})
|
||||
}
|
||||
@ -1314,13 +1344,43 @@ impl api::IncomingWebhook for Stripe {
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
|
||||
let details: stripe::StripeWebhookObjectResource = request
|
||||
let details: stripe::WebhookEventObjectResource = request
|
||||
.body
|
||||
.parse_struct("StripeWebhookObjectResource")
|
||||
.parse_struct("WebhookEventObjectResource")
|
||||
.change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
|
||||
|
||||
Ok(details.data.object)
|
||||
}
|
||||
fn get_dispute_details(
|
||||
&self,
|
||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||
) -> CustomResult<api::disputes::DisputePayload, errors::ConnectorError> {
|
||||
let details: stripe::WebhookEvent = request
|
||||
.body
|
||||
.parse_struct("WebhookEvent")
|
||||
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
|
||||
Ok(api::disputes::DisputePayload {
|
||||
amount: details.event_data.event_object.amount.to_string(),
|
||||
currency: details.event_data.event_object.currency,
|
||||
dispute_stage: api_models::enums::DisputeStage::Dispute,
|
||||
connector_dispute_id: details.event_data.event_object.id,
|
||||
connector_reason: details.event_data.event_object.reason,
|
||||
connector_reason_code: None,
|
||||
challenge_required_by: details
|
||||
.event_data
|
||||
.event_object
|
||||
.evidence_details
|
||||
.map(|payload| payload.due_by),
|
||||
connector_status: details
|
||||
.event_data
|
||||
.event_object
|
||||
.status
|
||||
.ok_or(errors::ConnectorError::WebhookResourceObjectNotFound)?
|
||||
.to_string(),
|
||||
created_at: Some(details.event_data.event_object.created),
|
||||
updated_at: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl services::ConnectorRedirectResponse for Stripe {
|
||||
|
||||
@ -4,6 +4,7 @@ use common_utils::{errors::CustomResult, pii};
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use masking::{ExposeInterface, ExposeOptionInterface, Secret};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -357,6 +358,20 @@ pub enum StripeBankNames {
|
||||
VanLanschot,
|
||||
}
|
||||
|
||||
impl TryFrom<WebhookEventStatus> for api_models::webhooks::IncomingWebhookEvent {
|
||||
type Error = errors::ConnectorError;
|
||||
fn try_from(value: WebhookEventStatus) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
WebhookEventStatus::WarningNeedsResponse => Self::DisputeOpened,
|
||||
WebhookEventStatus::WarningClosed => Self::DisputeCancelled,
|
||||
WebhookEventStatus::WarningUnderReview => Self::DisputeChallenged,
|
||||
WebhookEventStatus::Won => Self::DisputeWon,
|
||||
WebhookEventStatus::Lost => Self::DisputeLost,
|
||||
_ => Err(errors::ConnectorError::WebhookEventTypeNotFound)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&api_models::enums::BankNames> for StripeBankNames {
|
||||
type Error = errors::ConnectorError;
|
||||
fn try_from(bank: &api_models::enums::BankNames) -> Result<Self, Self::Error> {
|
||||
@ -1566,34 +1581,119 @@ impl<F, T>
|
||||
// }
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StripeWebhookDataObjectId {
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StripeWebhookDataId {
|
||||
pub object: StripeWebhookDataObjectId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StripeWebhookDataResource {
|
||||
pub struct WebhookEventDataResource {
|
||||
pub object: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StripeWebhookObjectResource {
|
||||
pub data: StripeWebhookDataResource,
|
||||
pub struct WebhookEventObjectResource {
|
||||
pub data: WebhookEventDataResource,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StripeWebhookObjectEventType {
|
||||
pub struct WebhookEvent {
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
pub event_type: WebhookEventType,
|
||||
#[serde(rename = "data")]
|
||||
pub event_data: WebhookEventData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StripeWebhookObjectId {
|
||||
pub data: StripeWebhookDataId,
|
||||
pub struct WebhookEventData {
|
||||
#[serde(rename = "object")]
|
||||
pub event_object: WebhookEventObjectData,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct WebhookEventObjectData {
|
||||
pub id: String,
|
||||
pub object: WebhookEventObjectType,
|
||||
pub amount: i32,
|
||||
pub currency: String,
|
||||
pub payment_intent: Option<String>,
|
||||
pub reason: Option<String>,
|
||||
#[serde(with = "common_utils::custom_serde::timestamp")]
|
||||
pub created: PrimitiveDateTime,
|
||||
pub evidence_details: Option<EvidenceDetails>,
|
||||
pub status: Option<WebhookEventStatus>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, strum::Display)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WebhookEventObjectType {
|
||||
PaymentIntent,
|
||||
Dispute,
|
||||
Charge,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub enum WebhookEventType {
|
||||
#[serde(rename = "payment_intent.payment_failed")]
|
||||
PaymentIntentFailed,
|
||||
#[serde(rename = "payment_intent.succeeded")]
|
||||
PaymentIntentSucceed,
|
||||
#[serde(rename = "charge.dispute.captured")]
|
||||
ChargeDisputeCaptured,
|
||||
#[serde(rename = "charge.dispute.created")]
|
||||
DisputeCreated,
|
||||
#[serde(rename = "charge.dispute.closed")]
|
||||
DisputeClosed,
|
||||
#[serde(rename = "charge.dispute.updated")]
|
||||
DisputeUpdated,
|
||||
#[serde(rename = "charge.dispute.funds_reinstated")]
|
||||
ChargeDisputeFundsReinstated,
|
||||
#[serde(rename = "charge.dispute.funds_withdrawn")]
|
||||
ChargeDisputeFundsWithdrawn,
|
||||
#[serde(rename = "charge.expired")]
|
||||
ChargeExpired,
|
||||
#[serde(rename = "charge.failed")]
|
||||
ChargeFailed,
|
||||
#[serde(rename = "charge.pending")]
|
||||
ChargePending,
|
||||
#[serde(rename = "charge.captured")]
|
||||
ChargeCaptured,
|
||||
#[serde(rename = "charge.succeeded")]
|
||||
ChargeSucceeded,
|
||||
#[serde(rename = "charge.updated")]
|
||||
ChargeUpdated,
|
||||
#[serde(rename = "charge.refunded")]
|
||||
ChanrgeRefunded,
|
||||
#[serde(rename = "payment_intent.canceled")]
|
||||
PaymentIntentCanceled,
|
||||
#[serde(rename = "payment_intent.created")]
|
||||
PaymentIntentCreated,
|
||||
#[serde(rename = "payment_intent.processing")]
|
||||
PaymentIntentProcessing,
|
||||
#[serde(rename = "payment_intent.requires_action")]
|
||||
PaymentIntentRequiresAction,
|
||||
#[serde(rename = "amount_capturable_updated")]
|
||||
PaymentIntentAmountCapturableUpdated,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, strum::Display, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WebhookEventStatus {
|
||||
WarningNeedsResponse,
|
||||
WarningClosed,
|
||||
WarningUnderReview,
|
||||
Won,
|
||||
Lost,
|
||||
NeedsResponse,
|
||||
UnderReview,
|
||||
ChargeRefunded,
|
||||
Succeeded,
|
||||
RequiresPaymentMethod,
|
||||
RequiresConfirmation,
|
||||
RequiresAction,
|
||||
Processing,
|
||||
RequiresCapture,
|
||||
Canceled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
pub struct EvidenceDetails {
|
||||
#[serde(with = "common_utils::custom_serde::timestamp")]
|
||||
pub due_by: PrimitiveDateTime,
|
||||
}
|
||||
|
||||
impl
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use masking::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{services, types};
|
||||
|
||||
@ -7,7 +8,7 @@ pub struct DisputeId {
|
||||
pub dispute_id: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct DisputePayload {
|
||||
pub amount: String,
|
||||
pub currency: String,
|
||||
@ -16,9 +17,9 @@ pub struct DisputePayload {
|
||||
pub connector_dispute_id: String,
|
||||
pub connector_reason: Option<String>,
|
||||
pub connector_reason_code: Option<String>,
|
||||
pub challenge_required_by: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
pub challenge_required_by: Option<PrimitiveDateTime>,
|
||||
pub created_at: Option<PrimitiveDateTime>,
|
||||
pub updated_at: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use common_utils::custom_serde;
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::{enums as storage_enums, schema::dispute};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Insertable, Serialize, router_derive::DebugAsDisplay)]
|
||||
#[derive(Clone, Debug, Insertable, Serialize, router_derive::DebugAsDisplay)]
|
||||
#[diesel(table_name = dispute)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct DisputeNew {
|
||||
@ -21,13 +21,13 @@ pub struct DisputeNew {
|
||||
pub connector_dispute_id: String,
|
||||
pub connector_reason: Option<String>,
|
||||
pub connector_reason_code: Option<String>,
|
||||
pub challenge_required_by: Option<String>,
|
||||
pub dispute_created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
pub challenge_required_by: Option<PrimitiveDateTime>,
|
||||
pub dispute_created_at: Option<PrimitiveDateTime>,
|
||||
pub updated_at: Option<PrimitiveDateTime>,
|
||||
pub connector: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, Identifiable, Queryable)]
|
||||
#[derive(Clone, Debug, Serialize, Identifiable, Queryable)]
|
||||
#[diesel(table_name = dispute)]
|
||||
pub struct Dispute {
|
||||
#[serde(skip_serializing)]
|
||||
@ -44,9 +44,9 @@ pub struct Dispute {
|
||||
pub connector_dispute_id: String,
|
||||
pub connector_reason: Option<String>,
|
||||
pub connector_reason_code: Option<String>,
|
||||
pub challenge_required_by: Option<String>,
|
||||
pub dispute_created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
pub challenge_required_by: Option<PrimitiveDateTime>,
|
||||
pub dispute_created_at: Option<PrimitiveDateTime>,
|
||||
pub updated_at: Option<PrimitiveDateTime>,
|
||||
#[serde(with = "custom_serde::iso8601")]
|
||||
pub created_at: PrimitiveDateTime,
|
||||
#[serde(with = "custom_serde::iso8601")]
|
||||
@ -62,8 +62,8 @@ pub enum DisputeUpdate {
|
||||
connector_status: String,
|
||||
connector_reason: Option<String>,
|
||||
connector_reason_code: Option<String>,
|
||||
challenge_required_by: Option<String>,
|
||||
updated_at: Option<String>,
|
||||
challenge_required_by: Option<PrimitiveDateTime>,
|
||||
updated_at: Option<PrimitiveDateTime>,
|
||||
},
|
||||
StatusUpdate {
|
||||
dispute_status: storage_enums::DisputeStatus,
|
||||
@ -79,8 +79,8 @@ pub struct DisputeUpdateInternal {
|
||||
connector_status: Option<String>,
|
||||
connector_reason: Option<String>,
|
||||
connector_reason_code: Option<String>,
|
||||
challenge_required_by: Option<String>,
|
||||
updated_at: Option<String>,
|
||||
challenge_required_by: Option<PrimitiveDateTime>,
|
||||
updated_at: Option<PrimitiveDateTime>,
|
||||
modified_at: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
|
||||
@ -128,9 +128,9 @@ diesel::table! {
|
||||
connector_dispute_id -> Varchar,
|
||||
connector_reason -> Nullable<Varchar>,
|
||||
connector_reason_code -> Nullable<Varchar>,
|
||||
challenge_required_by -> Nullable<Varchar>,
|
||||
dispute_created_at -> Nullable<Varchar>,
|
||||
updated_at -> Nullable<Varchar>,
|
||||
challenge_required_by -> Nullable<Timestamp>,
|
||||
dispute_created_at -> Nullable<Timestamp>,
|
||||
updated_at -> Nullable<Timestamp>,
|
||||
created_at -> Timestamp,
|
||||
modified_at -> Timestamp,
|
||||
connector -> Varchar,
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
ALTER TABLE dispute
|
||||
ALTER COLUMN challenge_required_by TYPE VARCHAR(255),
|
||||
ALTER COLUMN dispute_created_at TYPE VARCHAR(255),
|
||||
ALTER COLUMN updated_at TYPE VARCHAR(255)
|
||||
4
migrations/2023-04-26-062424_alter_dispute_table/up.sql
Normal file
4
migrations/2023-04-26-062424_alter_dispute_table/up.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE dispute
|
||||
ALTER COLUMN challenge_required_by TYPE TIMESTAMP USING dispute_created_at::TIMESTAMP,
|
||||
ALTER COLUMN dispute_created_at TYPE TIMESTAMP USING dispute_created_at::TIMESTAMP,
|
||||
ALTER COLUMN updated_at TYPE TIMESTAMP USING dispute_created_at::TIMESTAMP
|
||||
Reference in New Issue
Block a user