Skip to content

Commit

Permalink
feat(frm): Add support to accept and decline payment when manually re…
Browse files Browse the repository at this point in the history
…viewed by merchant for risky transaction (#2071)
  • Loading branch information
jagan-jaya authored Sep 4, 2023
1 parent c5003aa commit 229f111
Show file tree
Hide file tree
Showing 36 changed files with 1,382 additions and 78 deletions.
17 changes: 17 additions & 0 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1908,6 +1908,9 @@ pub struct PaymentsResponse {

/// total number of attempts associated with this payment
pub attempt_count: i16,

/// Denotes the action(approve or reject) taken by merchant in case of manual review. Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
pub merchant_decision: Option<String>,
}

#[derive(Clone, Debug, serde::Deserialize, ToSchema)]
Expand Down Expand Up @@ -2632,6 +2635,20 @@ pub struct PaymentsCancelRequest {
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
}

#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
pub struct PaymentsApproveRequest {
/// The identifier for the payment
#[serde(skip)]
pub payment_id: String,
}

#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
pub struct PaymentsRejectRequest {
/// The identifier for the payment
#[serde(skip)]
pub payment_id: String,
}

#[derive(Default, Debug, serde::Deserialize, serde::Serialize, ToSchema, Clone)]
pub struct PaymentsStartRequest {
/// Unique identifier for the payment. This ensures idempotency for multiple payments
Expand Down
23 changes: 22 additions & 1 deletion crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,25 @@ pub enum PayoutEntityType {
Personal,
}

#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
serde::Serialize,
serde::Deserialize,
strum::Display,
strum::EnumString,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[strum(serialize_all = "snake_case")]
pub enum MerchantDecision {
Approved,
Rejected,
AutoRefunded,
}

#[derive(
Clone,
Copy,
Expand All @@ -1691,9 +1710,11 @@ pub enum PayoutEntityType {
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum CancelTransaction {
pub enum FrmSuggestion {
#[default]
FrmCancelTransaction,
FrmManualReview,
FrmAutoRefund,
}

#[derive(
Expand Down
26 changes: 26 additions & 0 deletions crates/data_models/src/payments/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ pub struct PaymentIntent {
pub feature_metadata: Option<serde_json::Value>,
pub attempt_count: i16,
pub profile_id: Option<String>,
// Denotes the action(approve or reject) taken by merchant in case of manual review.
// Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
pub merchant_decision: Option<String>,
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -138,6 +141,7 @@ pub struct PaymentIntentNew {
pub feature_metadata: Option<serde_json::Value>,
pub attempt_count: i16,
pub profile_id: Option<String>,
pub merchant_decision: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -191,6 +195,13 @@ pub enum PaymentIntentUpdate {
active_attempt_id: String,
attempt_count: i16,
},
ApproveUpdate {
merchant_decision: Option<String>,
},
RejectUpdate {
status: storage_enums::IntentStatus,
merchant_decision: Option<String>,
},
}

#[derive(Clone, Debug, Default)]
Expand All @@ -215,6 +226,9 @@ pub struct PaymentIntentUpdateInternal {
pub statement_descriptor_suffix: Option<String>,
pub order_details: Option<Vec<pii::SecretSerdeValue>>,
pub attempt_count: Option<i16>,
// Denotes the action(approve or reject) taken by merchant in case of manual review.
// Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
pub merchant_decision: Option<String>,
}

impl PaymentIntentUpdate {
Expand Down Expand Up @@ -354,6 +368,18 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
attempt_count: Some(attempt_count),
..Default::default()
},
PaymentIntentUpdate::ApproveUpdate { merchant_decision } => Self {
merchant_decision,
..Default::default()
},
PaymentIntentUpdate::RejectUpdate {
status,
merchant_decision,
} => Self {
status: Some(status),
merchant_decision,
..Default::default()
},
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions crates/diesel_models/src/payment_attempt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,18 @@ pub enum PaymentAttemptUpdate {
payment_experience: Option<storage_enums::PaymentExperience>,
business_sub_label: Option<String>,
straight_through_algorithm: Option<serde_json::Value>,
error_code: Option<Option<String>>,
error_message: Option<Option<String>>,
},
VoidUpdate {
status: storage_enums::AttemptStatus,
cancellation_reason: Option<String>,
},
RejectUpdate {
status: storage_enums::AttemptStatus,
error_code: Option<Option<String>>,
error_message: Option<Option<String>>,
},
ResponseUpdate {
status: storage_enums::AttemptStatus,
connector: Option<String>,
Expand Down Expand Up @@ -321,6 +328,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
payment_experience,
business_sub_label,
straight_through_algorithm,
error_code,
error_message,
} => Self {
amount: Some(amount),
currency: Some(currency),
Expand All @@ -336,6 +345,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
payment_experience,
business_sub_label,
straight_through_algorithm,
error_code,
error_message,
..Default::default()
},
PaymentAttemptUpdate::VoidUpdate {
Expand All @@ -346,6 +357,16 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
cancellation_reason,
..Default::default()
},
PaymentAttemptUpdate::RejectUpdate {
status,
error_code,
error_message,
} => Self {
status: Some(status),
error_code,
error_message,
..Default::default()
},
PaymentAttemptUpdate::ResponseUpdate {
status,
connector,
Expand Down
24 changes: 24 additions & 0 deletions crates/diesel_models/src/payment_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub struct PaymentIntent {
pub feature_metadata: Option<serde_json::Value>,
pub attempt_count: i16,
pub profile_id: Option<String>,
// Denotes the action(approve or reject) taken by merchant in case of manual review.
// Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
pub merchant_decision: Option<String>,
}

#[derive(
Expand Down Expand Up @@ -92,6 +95,7 @@ pub struct PaymentIntentNew {
pub feature_metadata: Option<serde_json::Value>,
pub attempt_count: i16,
pub profile_id: Option<String>,
pub merchant_decision: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -145,6 +149,13 @@ pub enum PaymentIntentUpdate {
active_attempt_id: String,
attempt_count: i16,
},
ApproveUpdate {
merchant_decision: Option<String>,
},
RejectUpdate {
status: storage_enums::IntentStatus,
merchant_decision: Option<String>,
},
}

#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
Expand Down Expand Up @@ -172,6 +183,7 @@ pub struct PaymentIntentUpdateInternal {
#[diesel(deserialize_as = super::OptionalDieselArray<pii::SecretSerdeValue>)]
pub order_details: Option<Vec<pii::SecretSerdeValue>>,
pub attempt_count: Option<i16>,
merchant_decision: Option<String>,
}

impl PaymentIntentUpdate {
Expand Down Expand Up @@ -311,6 +323,18 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
attempt_count: Some(attempt_count),
..Default::default()
},
PaymentIntentUpdate::ApproveUpdate { merchant_decision } => Self {
merchant_decision,
..Default::default()
},
PaymentIntentUpdate::RejectUpdate {
status,
merchant_decision,
} => Self {
status: Some(status),
merchant_decision,
..Default::default()
},
}
}
}
2 changes: 2 additions & 0 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,8 @@ diesel::table! {
attempt_count -> Int2,
#[max_length = 64]
profile_id -> Nullable<Varchar>,
#[max_length = 64]
merchant_decision -> Nullable<Varchar>,
}
}

Expand Down
11 changes: 6 additions & 5 deletions crates/router/src/core/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ pub mod types;

use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant};

use api_models::payments::FrmMessage;
use common_utils::{ext_traits::AsyncExt, pii};
use diesel_models::ephemeral_key;
use diesel_models::{ephemeral_key, fraud_check::FraudCheck};
use error_stack::{IntoReport, ResultExt};
use futures::future::join_all;
use masking::Secret;
use router_env::{instrument, tracing};
use time;

pub use self::operations::{
PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate, PaymentMethodValidate,
PaymentResponse, PaymentSession, PaymentStatus, PaymentUpdate,
PaymentApprove, PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate,
PaymentMethodValidate, PaymentReject, PaymentResponse, PaymentSession, PaymentStatus,
PaymentUpdate,
};
use self::{
flows::{ConstructFlowSpecificData, Feature},
Expand Down Expand Up @@ -1146,7 +1146,7 @@ where
pub recurring_mandate_payment_data: Option<RecurringMandatePaymentData>,
pub ephemeral_key: Option<ephemeral_key::EphemeralKey>,
pub redirect_response: Option<api_models::payments::RedirectResponse>,
pub frm_message: Option<FrmMessage>,
pub frm_message: Option<FraudCheck>,
}

#[derive(Debug, Default, Clone)]
Expand Down Expand Up @@ -1239,6 +1239,7 @@ pub fn should_call_connector<Op: Debug, F: Clone>(
)
}
"CompleteAuthorize" => true,
"PaymentApprove" => true,
"PaymentSession" => true,
_ => false,
}
Expand Down
Loading

0 comments on commit 229f111

Please sign in to comment.