Skip to content

Commit 27debae

Browse files
Sayak BhattacharyaSayak Bhattacharya
authored andcommitted
feat(connector): [TRUSTPAY] Added Integrity Checks for PSync & RSync Flows & Added new variants in AttemptStatus & IntentStatus
1 parent 071b073 commit 27debae

File tree

16 files changed

+113
-29
lines changed

16 files changed

+113
-29
lines changed

crates/common_enums/src/enums.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub enum AttemptStatus {
153153
PaymentMethodAwaited,
154154
ConfirmationAwaited,
155155
DeviceDataCollectionPending,
156+
IntegrityFailure,
156157
}
157158

158159
impl AttemptStatus {
@@ -165,7 +166,8 @@ impl AttemptStatus {
165166
| Self::VoidFailed
166167
| Self::CaptureFailed
167168
| Self::Failure
168-
| Self::PartialCharged => true,
169+
| Self::PartialCharged
170+
| Self::IntegrityFailure => true,
169171
Self::Started
170172
| Self::AuthenticationFailed
171173
| Self::AuthenticationPending
@@ -1595,13 +1597,19 @@ pub enum IntentStatus {
15951597
PartiallyCaptured,
15961598
/// The payment has been captured partially and the remaining amount is capturable
15971599
PartiallyCapturedAndCapturable,
1600+
/// There has been a discrepancy between the amount sent in the request and the amount received by the processor
1601+
Conflicted,
15981602
}
15991603

16001604
impl IntentStatus {
16011605
/// Indicates whether the payment intent is in terminal state or not
16021606
pub fn is_in_terminal_state(self) -> bool {
16031607
match self {
1604-
Self::Succeeded | Self::Failed | Self::Cancelled | Self::PartiallyCaptured => true,
1608+
Self::Succeeded
1609+
| Self::Failed
1610+
| Self::Cancelled
1611+
| Self::PartiallyCaptured
1612+
| Self::Conflicted => true,
16051613
Self::Processing
16061614
| Self::RequiresCustomerAction
16071615
| Self::RequiresMerchantAction
@@ -1628,6 +1636,7 @@ impl IntentStatus {
16281636
| Self::RequiresCustomerAction
16291637
| Self::RequiresMerchantAction
16301638
| Self::PartiallyCapturedAndCapturable
1639+
| Self::Conflicted
16311640
=> true,
16321641
}
16331642
}
@@ -1743,7 +1752,8 @@ impl From<AttemptStatus> for PaymentMethodStatus {
17431752
| AttemptStatus::PartialCharged
17441753
| AttemptStatus::PartialChargedAndChargeable
17451754
| AttemptStatus::ConfirmationAwaited
1746-
| AttemptStatus::DeviceDataCollectionPending => Self::Inactive,
1755+
| AttemptStatus::DeviceDataCollectionPending
1756+
| AttemptStatus::IntegrityFailure => Self::Inactive,
17471757
AttemptStatus::Charged | AttemptStatus::Authorized => Self::Active,
17481758
}
17491759
}

crates/common_enums/src/transformers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2094,7 +2094,7 @@ impl From<AttemptStatus> for IntentStatus {
20942094
Self::RequiresCustomerAction
20952095
}
20962096
AttemptStatus::Unresolved => Self::RequiresMerchantAction,
2097-
2097+
AttemptStatus::IntegrityFailure => Self::Conflicted,
20982098
AttemptStatus::PartialCharged => Self::PartiallyCaptured,
20992099
AttemptStatus::PartialChargedAndChargeable => Self::PartiallyCapturedAndCapturable,
21002100
AttemptStatus::Started

crates/common_utils/src/types.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,11 @@ impl StringMajorUnit {
592592
Self(value)
593593
}
594594

595+
/// Direct Conversion of amount in f64 to StringMajorUnit
596+
pub fn f64_to_string_major_unit(amount: f64) -> Self {
597+
Self::new(amount.to_string())
598+
}
599+
595600
/// Converts to minor unit as i64 from StringMajorUnit
596601
fn to_minor_unit_as_i64(
597602
&self,

crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2525,7 +2525,8 @@ impl TryFrom<PaymentsCaptureResponseRouterData<PaypalCaptureResponse>>
25252525
| storage_enums::AttemptStatus::PaymentMethodAwaited
25262526
| storage_enums::AttemptStatus::ConfirmationAwaited
25272527
| storage_enums::AttemptStatus::DeviceDataCollectionPending
2528-
| storage_enums::AttemptStatus::Voided => 0,
2528+
| storage_enums::AttemptStatus::Voided
2529+
| storage_enums::AttemptStatus::IntegrityFailure => 0,
25292530
storage_enums::AttemptStatus::Charged
25302531
| storage_enums::AttemptStatus::PartialCharged
25312532
| storage_enums::AttemptStatus::PartialChargedAndChargeable => {

crates/hyperswitch_connectors/src/connectors/trustpay.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
pub mod transformers;
2-
32
use base64::Engine;
43
use common_enums::{enums, PaymentAction};
54
use common_utils::{
@@ -51,7 +50,7 @@ use transformers as trustpay;
5150
use crate::{
5251
constants::headers,
5352
types::ResponseRouterData,
54-
utils::{self, ConnectorErrorType, PaymentsPreProcessingRequestData},
53+
utils::{self, self as connector_utils, ConnectorErrorType, PaymentsPreProcessingRequestData},
5554
};
5655

5756
#[derive(Clone)]
@@ -415,6 +414,34 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Tru
415414
.parse_struct("trustpay PaymentsResponse")
416415
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
417416

417+
if let trustpay::TrustpayPaymentsResponse::WebhookResponse(ref webhook_response) = response
418+
{
419+
let amount = StringMajorUnit::f64_to_string_major_unit(webhook_response.amount.amount);
420+
let currency = webhook_response.amount.currency;
421+
422+
let response_integrity_object = connector_utils::get_sync_integrity_object(
423+
self.amount_converter,
424+
amount,
425+
currency.to_string(),
426+
)?;
427+
428+
event_builder.map(|i| i.set_response_body(&response));
429+
router_env::logger::info!(connector_response=?response);
430+
431+
let new_router_data = RouterData::try_from(ResponseRouterData {
432+
response,
433+
data: data.clone(),
434+
http_code: res.status_code,
435+
});
436+
437+
return new_router_data
438+
.map(|mut router_data| {
439+
router_data.request.integrity_object = Some(response_integrity_object);
440+
router_data
441+
})
442+
.change_context(errors::ConnectorError::ResponseHandlingFailed);
443+
}
444+
418445
event_builder.map(|i| i.set_response_body(&response));
419446
router_env::logger::info!(connector_response=?response);
420447

@@ -801,6 +828,32 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Trustpay
801828
.parse_struct("trustpay RefundResponse")
802829
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
803830

831+
if let trustpay::RefundResponse::WebhookRefund(ref webhook_response) = response {
832+
let currency = webhook_response.amount.currency;
833+
834+
let amount = StringMajorUnit::f64_to_string_major_unit(webhook_response.amount.amount);
835+
let response_integrity_object = connector_utils::get_refund_integrity_object(
836+
self.amount_converter,
837+
amount,
838+
currency.to_string(),
839+
)?;
840+
841+
event_builder.map(|i| i.set_response_body(&response));
842+
router_env::logger::info!(connector_response=?response);
843+
844+
let new_router_data = RouterData::try_from(ResponseRouterData {
845+
response,
846+
data: data.clone(),
847+
http_code: res.status_code,
848+
});
849+
850+
return new_router_data
851+
.map(|mut router_data| {
852+
router_data.request.integrity_object = Some(response_integrity_object);
853+
router_data
854+
})
855+
.change_context(errors::ConnectorError::ResponseHandlingFailed);
856+
}
804857
event_builder.map(|i| i.set_response_body(&response));
805858
router_env::logger::info!(connector_response=?response);
806859

crates/hyperswitch_connectors/src/utils.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ pub(crate) fn is_payment_failure(status: AttemptStatus) -> bool {
426426
| AttemptStatus::AuthorizationFailed
427427
| AttemptStatus::CaptureFailed
428428
| AttemptStatus::VoidFailed
429-
| AttemptStatus::Failure => true,
429+
| AttemptStatus::Failure
430+
| AttemptStatus::IntegrityFailure => true,
430431
AttemptStatus::Started
431432
| AttemptStatus::RouterDeclined
432433
| AttemptStatus::AuthenticationPending
@@ -6170,7 +6171,8 @@ impl FrmTransactionRouterDataRequest for FrmTransactionRouterData {
61706171
| AttemptStatus::Voided
61716172
| AttemptStatus::CaptureFailed
61726173
| AttemptStatus::Failure
6173-
| AttemptStatus::AutoRefunded => Some(false),
6174+
| AttemptStatus::AutoRefunded
6175+
| AttemptStatus::IntegrityFailure => Some(false),
61746176

61756177
AttemptStatus::AuthenticationSuccessful
61766178
| AttemptStatus::PartialChargedAndChargeable

crates/router/src/compatibility/stripe/payment_intents/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ impl From<api_enums::IntentStatus> for StripePaymentStatus {
423423
api_enums::IntentStatus::Failed => Self::Canceled,
424424
api_enums::IntentStatus::Processing => Self::Processing,
425425
api_enums::IntentStatus::RequiresCustomerAction
426-
| api_enums::IntentStatus::RequiresMerchantAction => Self::RequiresAction,
426+
| api_enums::IntentStatus::RequiresMerchantAction
427+
| api_enums::IntentStatus::Conflicted => Self::RequiresAction,
427428
api_enums::IntentStatus::RequiresPaymentMethod => Self::RequiresPaymentMethod,
428429
api_enums::IntentStatus::RequiresConfirmation => Self::RequiresConfirmation,
429430
api_enums::IntentStatus::RequiresCapture

crates/router/src/compatibility/stripe/setup_intents/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,8 @@ impl From<api_enums::IntentStatus> for StripeSetupStatus {
315315
api_enums::IntentStatus::Failed => Self::Canceled,
316316
api_enums::IntentStatus::Processing => Self::Processing,
317317
api_enums::IntentStatus::RequiresCustomerAction => Self::RequiresAction,
318-
api_enums::IntentStatus::RequiresMerchantAction => Self::RequiresAction,
318+
api_enums::IntentStatus::RequiresMerchantAction
319+
| api_enums::IntentStatus::Conflicted => Self::RequiresAction,
319320
api_enums::IntentStatus::RequiresPaymentMethod => Self::RequiresPaymentMethod,
320321
api_enums::IntentStatus::RequiresConfirmation => Self::RequiresConfirmation,
321322
api_enums::IntentStatus::RequiresCapture

crates/router/src/connector/utils.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,8 @@ impl FrmTransactionRouterDataRequest for fraud_check::FrmTransactionRouterData {
22062206
| storage_enums::AttemptStatus::Voided
22072207
| storage_enums::AttemptStatus::CaptureFailed
22082208
| storage_enums::AttemptStatus::Failure
2209-
| storage_enums::AttemptStatus::AutoRefunded => Some(false),
2209+
| storage_enums::AttemptStatus::AutoRefunded
2210+
| storage_enums::AttemptStatus::IntegrityFailure => Some(false),
22102211

22112212
storage_enums::AttemptStatus::AuthenticationSuccessful
22122213
| storage_enums::AttemptStatus::PartialChargedAndChargeable
@@ -2236,7 +2237,8 @@ pub fn is_payment_failure(status: enums::AttemptStatus) -> bool {
22362237
| common_enums::AttemptStatus::AuthorizationFailed
22372238
| common_enums::AttemptStatus::CaptureFailed
22382239
| common_enums::AttemptStatus::VoidFailed
2239-
| common_enums::AttemptStatus::Failure => true,
2240+
| common_enums::AttemptStatus::Failure
2241+
| common_enums::AttemptStatus::IntegrityFailure => true,
22402242
common_enums::AttemptStatus::Started
22412243
| common_enums::AttemptStatus::RouterDeclined
22422244
| common_enums::AttemptStatus::AuthenticationPending

crates/router/src/core/payments/helpers.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4229,7 +4229,8 @@ pub fn get_attempt_type(
42294229

42304230
storage_enums::AttemptStatus::VoidFailed
42314231
| storage_enums::AttemptStatus::RouterDeclined
4232-
| storage_enums::AttemptStatus::CaptureFailed => {
4232+
| storage_enums::AttemptStatus::CaptureFailed
4233+
| storage_enums::AttemptStatus::IntegrityFailure => {
42334234
metrics::MANUAL_RETRY_VALIDATION_FAILED.add(
42344235
1,
42354236
router_env::metric_attributes!((
@@ -4270,7 +4271,8 @@ pub fn get_attempt_type(
42704271
| enums::IntentStatus::PartiallyCaptured
42714272
| enums::IntentStatus::PartiallyCapturedAndCapturable
42724273
| enums::IntentStatus::Processing
4273-
| enums::IntentStatus::Succeeded => {
4274+
| enums::IntentStatus::Succeeded
4275+
| enums::IntentStatus::Conflicted => {
42744276
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
42754277
message: format!(
42764278
"You cannot {action} this payment because it has status {}",
@@ -4521,7 +4523,8 @@ pub fn is_manual_retry_allowed(
45214523

45224524
storage_enums::AttemptStatus::VoidFailed
45234525
| storage_enums::AttemptStatus::RouterDeclined
4524-
| storage_enums::AttemptStatus::CaptureFailed => Some(false),
4526+
| storage_enums::AttemptStatus::CaptureFailed
4527+
| storage_enums::AttemptStatus::IntegrityFailure => Some(false),
45254528

45264529
storage_enums::AttemptStatus::AuthenticationFailed
45274530
| storage_enums::AttemptStatus::AuthorizationFailed
@@ -4532,7 +4535,8 @@ pub fn is_manual_retry_allowed(
45324535
| enums::IntentStatus::PartiallyCaptured
45334536
| enums::IntentStatus::PartiallyCapturedAndCapturable
45344537
| enums::IntentStatus::Processing
4535-
| enums::IntentStatus::Succeeded => Some(false),
4538+
| enums::IntentStatus::Succeeded
4539+
| enums::IntentStatus::Conflicted => Some(false),
45364540

45374541
enums::IntentStatus::RequiresCustomerAction
45384542
| enums::IntentStatus::RequiresMerchantAction

0 commit comments

Comments
 (0)