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
2 changes: 1 addition & 1 deletion crates/router/src/connector/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ where
}
enums::AttemptStatus::Charged => {
let captured_amount =
types::Capturable::get_capture_amount(&self.request, payment_data);
types::Capturable::get_captured_amount(&self.request, payment_data);
let total_capturable_amount = payment_data.payment_attempt.get_total_amount();
if Some(total_capturable_amount) == captured_amount {
enums::AttemptStatus::Charged
Expand Down
68 changes: 30 additions & 38 deletions crates/router/src/core/payments/operations/payment_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
services::RedirectForm,
types::{
self, api,
storage::{self, enums, payment_attempt::AttemptStatusExt},
storage::{self, enums},
transformers::{ForeignFrom, ForeignTryFrom},
CaptureSyncResponse,
},
Expand Down Expand Up @@ -499,15 +499,9 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
error_message: Some(Some(err.message)),
error_code: Some(Some(err.code)),
error_reason: Some(err.reason),
amount_capturable: if status.is_terminal_status()
|| router_data
.status
.maps_to_intent_status(enums::IntentStatus::Processing)
{
Some(0)
} else {
None
},
amount_capturable: router_data
.request
.get_amount_capturable(&payment_data, status),
updated_by: storage_scheme.to_string(),
unified_code: option_gsm.clone().map(|gsm| gsm.unified_code),
unified_message: option_gsm.map(|gsm| gsm.unified_message),
Expand Down Expand Up @@ -598,27 +592,33 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
payment_data.payment_attempt.merchant_id.clone(),
);

let (capture_updates, payment_attempt_update) =
match payment_data.multiple_capture_data {
Some(multiple_capture_data) => {
let capture_update = storage::CaptureUpdate::ResponseUpdate {
status: enums::CaptureStatus::foreign_try_from(router_data.status)?,
connector_capture_id: connector_transaction_id.clone(),
connector_response_reference_id,
};
let capture_update_list = vec![(
multiple_capture_data.get_latest_capture().clone(),
capture_update,
)];
(Some((multiple_capture_data, capture_update_list)), None)
}
None => (
let (capture_updates, payment_attempt_update) = match payment_data
.multiple_capture_data
{
Some(multiple_capture_data) => {
let capture_update = storage::CaptureUpdate::ResponseUpdate {
status: enums::CaptureStatus::foreign_try_from(router_data.status)?,
connector_capture_id: connector_transaction_id.clone(),
connector_response_reference_id,
};
let capture_update_list = vec![(
multiple_capture_data.get_latest_capture().clone(),
capture_update,
)];
(Some((multiple_capture_data, capture_update_list)), None)
}
None => {
let status = router_data.get_attempt_status_for_db_update(&payment_data);
(
None,
Some(storage::PaymentAttemptUpdate::ResponseUpdate {
status: router_data.get_attempt_status_for_db_update(&payment_data),
status,
connector: None,
connector_transaction_id: connector_transaction_id.clone(),
authentication_type: None,
amount_capturable: router_data
.request
.get_amount_capturable(&payment_data, status),
payment_method_id: Some(router_data.payment_method_id),
mandate_id: payment_data
.mandate_id
Expand All @@ -632,21 +632,13 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
unified_code: error_status.clone(),
unified_message: error_status,
connector_response_reference_id,
amount_capturable: if router_data.status.is_terminal_status()
|| router_data
.status
.maps_to_intent_status(enums::IntentStatus::Processing)
{
Some(0)
} else {
None
},
updated_by: storage_scheme.to_string(),
authentication_data,
encoded_data,
}),
),
};
)
}
};

(capture_updates, payment_attempt_update)
}
Expand Down Expand Up @@ -900,7 +892,7 @@ fn get_total_amount_captured<F: Clone, T: types::Capturable>(
}
None => {
//Non multiple capture
let amount = request.get_capture_amount(payment_data);
let amount = request.get_captured_amount(payment_data);
amount_captured.or_else(|| {
if router_data_status == enums::AttemptStatus::Charged {
amount
Expand Down
168 changes: 161 additions & 7 deletions crates/router/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,17 @@ pub struct AccessTokenRequestData {
}

pub trait Capturable {
fn get_capture_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
fn get_captured_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
where
F: Clone,
{
None
}
fn get_amount_capturable<F>(
&self,
_payment_data: &PaymentData<F>,
_attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
Expand All @@ -592,7 +602,7 @@ pub trait Capturable {
}

impl Capturable for PaymentsAuthorizeData {
fn get_capture_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
fn get_captured_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
where
F: Clone,
{
Expand All @@ -602,41 +612,171 @@ impl Capturable for PaymentsAuthorizeData {
.map(|surcharge_details| surcharge_details.final_amount);
final_amount.or(Some(self.amount))
}

fn get_amount_capturable<F>(
&self,
payment_data: &PaymentData<F>,
attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
match payment_data
.payment_attempt
.capture_method
.unwrap_or_default()
{
common_enums::CaptureMethod::Automatic => {
let intent_status = common_enums::IntentStatus::foreign_from(attempt_status);
match intent_status {
common_enums::IntentStatus::Succeeded
| common_enums::IntentStatus::Failed
| common_enums::IntentStatus::Processing => Some(0),
common_enums::IntentStatus::Cancelled
| common_enums::IntentStatus::PartiallyCaptured
| common_enums::IntentStatus::RequiresCustomerAction
| common_enums::IntentStatus::RequiresMerchantAction
| common_enums::IntentStatus::RequiresPaymentMethod
| common_enums::IntentStatus::RequiresConfirmation
| common_enums::IntentStatus::RequiresCapture
| common_enums::IntentStatus::PartiallyCapturedAndCapturable => None,
}
},
common_enums::CaptureMethod::Manual => Some(payment_data.payment_attempt.get_total_amount()),
// In case of manual multiple, amount capturable must be inferred from all captures.
common_enums::CaptureMethod::ManualMultiple |
// Scheduled capture is not supported as of now
common_enums::CaptureMethod::Scheduled => None,
}
}
}

impl Capturable for PaymentsCaptureData {
fn get_capture_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
fn get_captured_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
where
F: Clone,
{
Some(self.amount_to_capture)
}
fn get_amount_capturable<F>(
&self,
_payment_data: &PaymentData<F>,
attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
let intent_status = common_enums::IntentStatus::foreign_from(attempt_status);
match intent_status {
common_enums::IntentStatus::Succeeded
| common_enums::IntentStatus::PartiallyCaptured
| common_enums::IntentStatus::Processing => Some(0),
common_enums::IntentStatus::Cancelled
| common_enums::IntentStatus::Failed
| common_enums::IntentStatus::RequiresCustomerAction
| common_enums::IntentStatus::RequiresMerchantAction
| common_enums::IntentStatus::RequiresPaymentMethod
| common_enums::IntentStatus::RequiresConfirmation
| common_enums::IntentStatus::RequiresCapture
| common_enums::IntentStatus::PartiallyCapturedAndCapturable => None,
}
}
}

impl Capturable for CompleteAuthorizeData {
fn get_capture_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
fn get_captured_amount<F>(&self, _payment_data: &PaymentData<F>) -> Option<i64>
where
F: Clone,
{
Some(self.amount)
}
fn get_amount_capturable<F>(
&self,
payment_data: &PaymentData<F>,
attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
match payment_data
.payment_attempt
.capture_method
.unwrap_or_default()
{
common_enums::CaptureMethod::Automatic => {
let intent_status = common_enums::IntentStatus::foreign_from(attempt_status);
match intent_status {
common_enums::IntentStatus::Succeeded|
common_enums::IntentStatus::Failed|
common_enums::IntentStatus::Processing => Some(0),
common_enums::IntentStatus::Cancelled
| common_enums::IntentStatus::PartiallyCaptured
| common_enums::IntentStatus::RequiresCustomerAction
| common_enums::IntentStatus::RequiresMerchantAction
| common_enums::IntentStatus::RequiresPaymentMethod
| common_enums::IntentStatus::RequiresConfirmation
| common_enums::IntentStatus::RequiresCapture
| common_enums::IntentStatus::PartiallyCapturedAndCapturable => None,
}
},
common_enums::CaptureMethod::Manual => Some(payment_data.payment_attempt.get_total_amount()),
// In case of manual multiple, amount capturable must be inferred from all captures.
common_enums::CaptureMethod::ManualMultiple |
// Scheduled capture is not supported as of now
common_enums::CaptureMethod::Scheduled => None,
}
}
}
impl Capturable for SetupMandateRequestData {}
impl Capturable for PaymentsCancelData {
fn get_capture_amount<F>(&self, payment_data: &PaymentData<F>) -> Option<i64>
fn get_captured_amount<F>(&self, payment_data: &PaymentData<F>) -> Option<i64>
where
F: Clone,
{
// return previously captured amount
payment_data.payment_intent.amount_captured
}
fn get_amount_capturable<F>(
&self,
_payment_data: &PaymentData<F>,
attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
let intent_status = common_enums::IntentStatus::foreign_from(attempt_status);
match intent_status {
common_enums::IntentStatus::Cancelled
| common_enums::IntentStatus::Processing
| common_enums::IntentStatus::PartiallyCaptured => Some(0),
common_enums::IntentStatus::Succeeded
| common_enums::IntentStatus::Failed
| common_enums::IntentStatus::RequiresCustomerAction
| common_enums::IntentStatus::RequiresMerchantAction
| common_enums::IntentStatus::RequiresPaymentMethod
| common_enums::IntentStatus::RequiresConfirmation
| common_enums::IntentStatus::RequiresCapture
| common_enums::IntentStatus::PartiallyCapturedAndCapturable => None,
}
}
}
impl Capturable for PaymentsApproveData {}
impl Capturable for PaymentsRejectData {}
impl Capturable for PaymentsSessionData {}
impl Capturable for PaymentsIncrementalAuthorizationData {}
impl Capturable for PaymentsIncrementalAuthorizationData {
fn get_amount_capturable<F>(
&self,
_payment_data: &PaymentData<F>,
_attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
Some(self.total_amount)
}
}
impl Capturable for PaymentsSyncData {
fn get_capture_amount<F>(&self, payment_data: &PaymentData<F>) -> Option<i64>
fn get_captured_amount<F>(&self, payment_data: &PaymentData<F>) -> Option<i64>
where
F: Clone,
{
Expand All @@ -645,6 +785,20 @@ impl Capturable for PaymentsSyncData {
.amount_to_capture
.or_else(|| Some(payment_data.payment_attempt.get_total_amount()))
}
fn get_amount_capturable<F>(
&self,
_payment_data: &PaymentData<F>,
attempt_status: common_enums::AttemptStatus,
) -> Option<i64>
where
F: Clone,
{
if attempt_status.is_terminal_status() {
Some(0)
} else {
None
}
}
}

pub struct AddAccessTokenResult {
Expand Down