Skip to content
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(core): Create Payout Webhook Flow #4696

Merged
merged 26 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6987b9e
feat: create payout webhook flow
Sakilmostak May 17, 2024
cc3acce
feat: add payout webhooks to adyen
Sakilmostak May 19, 2024
83b317c
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] May 19, 2024
5707288
refactor: resolve ci checks
Sakilmostak May 19, 2024
a500203
refactor: resolve msrv check
Sakilmostak May 19, 2024
8457acb
refactor: use payout_attempt_id as connector_request_reference_id
Sakilmostak May 20, 2024
2c8d279
refactor: add necessary feature flags
Sakilmostak May 27, 2024
730f7cd
Merge branch 'main' into payouts_webhook
Sakilmostak May 27, 2024
e06c78a
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] May 27, 2024
3d062e4
refactor: resolve ci checks
Sakilmostak May 27, 2024
db57662
refactor: comments
Sakilmostak May 27, 2024
834a394
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] May 27, 2024
7c8a896
refactor: add feature flags to enums
Sakilmostak May 29, 2024
0f1f62f
refactor: merge main
Sakilmostak May 30, 2024
d68e801
refactor: resolve conflict with main
Sakilmostak May 30, 2024
94f8ea2
refactor: convert created to intiated
Sakilmostak May 31, 2024
db98a7b
chore: run formatter
hyperswitch-bot[bot] May 31, 2024
322e980
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] May 31, 2024
a7c466f
refactor: spell check
Sakilmostak Jun 4, 2024
e4bfb1d
refactor: resolve clippy
Sakilmostak Jun 4, 2024
feb8653
refactor: feature flag for AppState
Sakilmostak Jun 4, 2024
22733ca
Merge branch 'main' into payouts_webhook
Sakilmostak Jun 4, 2024
407f17c
refactor: resolve conflict with main
Sakilmostak Jun 4, 2024
39973a2
refactor: resolve comments
Sakilmostak Jun 4, 2024
7d11db3
refactor: resolve comments
Sakilmostak Jun 4, 2024
2ebb4d5
refactor: comments
Sakilmostak Jun 4, 2024
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
45 changes: 45 additions & 0 deletions crates/api_models/src/webhooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use utoipa::ToSchema;

#[cfg(feature = "payouts")]
use crate::payouts;
use crate::{disputes, enums as api_enums, mandates, payments, refunds};

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Copy)]
Expand Down Expand Up @@ -41,10 +43,26 @@ pub enum IncomingWebhookEvent {
ExternalAuthenticationARes,
FrmApproved,
FrmRejected,
#[cfg(feature = "payouts")]
PayoutSuccess,
#[cfg(feature = "payouts")]
PayoutFailure,
#[cfg(feature = "payouts")]
PayoutProcessing,
#[cfg(feature = "payouts")]
PayoutCancelled,
#[cfg(feature = "payouts")]
PayoutCreated,
#[cfg(feature = "payouts")]
PayoutExpired,
#[cfg(feature = "payouts")]
PayoutReversed,
}

pub enum WebhookFlow {
Payment,
#[cfg(feature = "payouts")]
Payout,
Refund,
Dispute,
Subscription,
Expand All @@ -62,6 +80,11 @@ pub enum WebhookResponseTracker {
payment_id: String,
status: common_enums::IntentStatus,
},
#[cfg(feature = "payouts")]
Payout {
payout_id: String,
status: common_enums::PayoutStatus,
},
Refund {
payment_id: String,
refund_id: String,
Expand All @@ -86,6 +109,8 @@ impl WebhookResponseTracker {
| Self::Refund { payment_id, .. }
| Self::Dispute { payment_id, .. } => Some(payment_id.to_string()),
Self::NoEffect | Self::Mandate { .. } => None,
#[cfg(feature = "payouts")]
Self::Payout { .. } => None,
}
}
}
Expand Down Expand Up @@ -125,6 +150,14 @@ impl From<IncomingWebhookEvent> for WebhookFlow {
IncomingWebhookEvent::FrmApproved | IncomingWebhookEvent::FrmRejected => {
Self::FraudCheck
}
#[cfg(feature = "payouts")]
IncomingWebhookEvent::PayoutSuccess
| IncomingWebhookEvent::PayoutFailure
| IncomingWebhookEvent::PayoutProcessing
| IncomingWebhookEvent::PayoutCancelled
| IncomingWebhookEvent::PayoutCreated
| IncomingWebhookEvent::PayoutExpired
| IncomingWebhookEvent::PayoutReversed => Self::Payout,
}
}
}
Expand All @@ -149,12 +182,21 @@ pub enum AuthenticationIdType {
ConnectorAuthenticationId(String),
}

#[cfg(feature = "payouts")]
#[derive(Clone)]
pub enum PayoutIdType {
PayoutAttemptId(String),
ConnectorPayoutId(String),
}

#[derive(Clone)]
pub enum ObjectReferenceId {
PaymentId(payments::PaymentIdType),
RefundId(RefundIdType),
MandateId(MandateIdType),
ExternalAuthenticationID(AuthenticationIdType),
#[cfg(feature = "payouts")]
PayoutId(PayoutIdType),
}

pub struct IncomingWebhookDetails {
Expand Down Expand Up @@ -193,6 +235,9 @@ pub enum OutgoingWebhookContent {
DisputeDetails(Box<disputes::DisputeResponse>),
#[schema(value_type = MandateResponse, title = "MandateResponse")]
MandateDetails(Box<mandates::MandateResponse>),
#[cfg(feature = "payouts")]
#[schema(value_type = PayoutCreateResponse, title = "PayoutCreateResponse")]
PayoutDetails(payouts::PayoutCreateResponse),
}

#[derive(Debug, Clone, Serialize)]
Expand Down
12 changes: 12 additions & 0 deletions crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,8 @@ pub enum EventClass {
Refunds,
Disputes,
Mandates,
#[cfg(feature = "payouts")]
Payouts,
}

#[derive(
Expand Down Expand Up @@ -1107,6 +1109,13 @@ pub enum EventType {
DisputeLost,
MandateActive,
MandateRevoked,
PayoutSuccess,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible to add PayoutCreated? Trigger - when payout is created at connector's end.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we add feature flags here as well?

PayoutFailed,
PayoutInitiated,
PayoutProcessing,
PayoutCancelled,
PayoutExpired,
PayoutReversed,
}

#[derive(
Expand Down Expand Up @@ -2116,6 +2125,9 @@ pub enum PayoutStatus {
Success,
Failed,
Cancelled,
Initiated,
Expired,
Reversed,
Pending,
Ineligible,
#[default]
Expand Down
1 change: 1 addition & 0 deletions crates/diesel_models/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub enum EventObjectType {
RefundDetails,
DisputeDetails,
MandateDetails,
PayoutDetails,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feature flag?

}

#[derive(
Expand Down
10 changes: 5 additions & 5 deletions crates/diesel_models/src/payout_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct PayoutAttempt {
pub merchant_id: String,
pub address_id: String,
pub connector: Option<String>,
pub connector_payout_id: String,
pub connector_payout_id: Option<String>,
pub payout_token: Option<String>,
pub status: storage_enums::PayoutStatus,
pub is_eligible: Option<bool>,
Expand Down Expand Up @@ -51,7 +51,7 @@ pub struct PayoutAttemptNew {
pub merchant_id: String,
pub address_id: String,
pub connector: Option<String>,
pub connector_payout_id: String,
pub connector_payout_id: Option<String>,
pub payout_token: Option<String>,
pub status: storage_enums::PayoutStatus,
pub is_eligible: Option<bool>,
Expand All @@ -71,7 +71,7 @@ pub struct PayoutAttemptNew {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PayoutAttemptUpdate {
StatusUpdate {
connector_payout_id: String,
connector_payout_id: Option<String>,
status: storage_enums::PayoutStatus,
error_message: Option<String>,
error_code: Option<String>,
Expand Down Expand Up @@ -138,7 +138,7 @@ impl From<PayoutAttemptUpdate> for PayoutAttemptUpdateInternal {
error_code,
is_eligible,
} => Self {
connector_payout_id: Some(connector_payout_id),
connector_payout_id,
status: Some(status),
error_message,
error_code,
Expand Down Expand Up @@ -182,7 +182,7 @@ impl PayoutAttemptUpdate {
} = self.into();
PayoutAttempt {
payout_token: payout_token.or(source.payout_token),
connector_payout_id: connector_payout_id.unwrap_or(source.connector_payout_id),
connector_payout_id: connector_payout_id.or(source.connector_payout_id),
status: status.unwrap_or(source.status),
error_message: error_message.or(source.error_message),
error_code: error_code.or(source.error_code),
Expand Down
14 changes: 14 additions & 0 deletions crates/diesel_models/src/query/payout_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ impl PayoutAttempt {
.await
}

pub async fn find_by_merchant_id_connector_payout_id(
conn: &PgPooledConn,
merchant_id: &str,
connector_payout_id: &str,
) -> StorageResult<Self> {
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
conn,
dsl::merchant_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please create an index for merchant_id, connector_payout_id

.eq(merchant_id.to_owned())
.and(dsl::connector_payout_id.eq(connector_payout_id.to_owned())),
)
.await
}

pub async fn update_by_merchant_id_payout_id(
conn: &PgPooledConn,
merchant_id: &str,
Expand Down
2 changes: 1 addition & 1 deletion crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ diesel::table! {
#[max_length = 64]
connector -> Nullable<Varchar>,
#[max_length = 128]
connector_payout_id -> Varchar,
connector_payout_id -> Nullable<Varchar>,
#[max_length = 64]
payout_token -> Nullable<Varchar>,
status -> PayoutStatus,
Expand Down
19 changes: 13 additions & 6 deletions crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ pub trait PayoutAttemptInterface {
_storage_scheme: MerchantStorageScheme,
) -> error_stack::Result<PayoutAttempt, errors::StorageError>;

async fn find_payout_attempt_by_merchant_id_connector_payout_id(
&self,
_merchant_id: &str,
_connector_payout_id: &str,
_storage_scheme: MerchantStorageScheme,
) -> error_stack::Result<PayoutAttempt, errors::StorageError>;

async fn get_filters_for_payouts(
&self,
payout: &[Payouts],
Expand All @@ -56,7 +63,7 @@ pub struct PayoutAttempt {
pub merchant_id: String,
pub address_id: String,
pub connector: Option<String>,
pub connector_payout_id: String,
pub connector_payout_id: Option<String>,
pub payout_token: Option<String>,
pub status: storage_enums::PayoutStatus,
pub is_eligible: Option<bool>,
Expand All @@ -81,7 +88,7 @@ pub struct PayoutAttemptNew {
pub merchant_id: String,
pub address_id: String,
pub connector: Option<String>,
pub connector_payout_id: String,
pub connector_payout_id: Option<String>,
pub payout_token: Option<String>,
pub status: storage_enums::PayoutStatus,
pub is_eligible: Option<bool>,
Expand All @@ -107,7 +114,7 @@ impl Default for PayoutAttemptNew {
merchant_id: String::default(),
address_id: String::default(),
connector: None,
connector_payout_id: String::default(),
connector_payout_id: Some(String::default()),
payout_token: None,
status: storage_enums::PayoutStatus::default(),
is_eligible: None,
Expand All @@ -124,10 +131,10 @@ impl Default for PayoutAttemptNew {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum PayoutAttemptUpdate {
StatusUpdate {
connector_payout_id: String,
connector_payout_id: Option<String>,
status: storage_enums::PayoutStatus,
error_message: Option<String>,
error_code: Option<String>,
Expand Down Expand Up @@ -174,7 +181,7 @@ impl From<PayoutAttemptUpdate> for PayoutAttemptUpdateInternal {
error_code,
is_eligible,
} => Self {
connector_payout_id: Some(connector_payout_id),
connector_payout_id,
status: Some(status),
error_message,
error_code,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ pub struct RetrieveFileResponse {
#[derive(Clone, Debug, Default)]
pub struct PayoutsResponseData {
pub status: Option<common_enums::PayoutStatus>,
pub connector_payout_id: String,
pub connector_payout_id: Option<String>,
pub payout_eligible: Option<bool>,
pub should_add_next_step_to_process_tracker: bool,
}
Expand Down
Loading
Loading