From 8cf1f75fb1705aa020db5f966e15c3d9a80dd908 Mon Sep 17 00:00:00 2001 From: SamraatBansal <55536657+SamraatBansal@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:18:05 +0530 Subject: [PATCH] fix(core): Update Webhooks Event Mapping and Forced Psync preconditions (#1970) Co-authored-by: swangi-kumari --- crates/router/src/core/payments.rs | 6 +- crates/router/src/core/payments/helpers.rs | 1 - crates/router/src/core/webhooks.rs | 108 ++++++++---------- crates/router/src/types/transformers.rs | 62 +++++----- .../tests/connectors/adyen_uk_ui.rs | 4 +- openapi/openapi_spec.json | 15 ++- 6 files changed, 99 insertions(+), 97 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index d8617f4231..6f1dee662c 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1306,11 +1306,11 @@ pub fn should_call_connector( "PaymentStatus" => { matches!( payment_data.payment_intent.status, - storage_enums::IntentStatus::Failed - | storage_enums::IntentStatus::Processing - | storage_enums::IntentStatus::Succeeded + storage_enums::IntentStatus::Processing | storage_enums::IntentStatus::RequiresCustomerAction | storage_enums::IntentStatus::RequiresMerchantAction + | storage_enums::IntentStatus::RequiresCapture + | storage_enums::IntentStatus::PartiallyCaptured ) && payment_data.force_sync.unwrap_or(false) } "PaymentCancel" => matches!( diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 98b63dc3a1..89f2217e10 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1646,7 +1646,6 @@ pub fn check_force_psync_precondition( | storage_enums::AttemptStatus::AutoRefunded | storage_enums::AttemptStatus::Voided | storage_enums::AttemptStatus::CodInitiated - | storage_enums::AttemptStatus::Authorized | storage_enums::AttemptStatus::Started | storage_enums::AttemptStatus::Failure ) && connector_transaction_id.is_some() diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index be300861d7..a5399c61f3 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -101,24 +101,22 @@ pub async fn payments_incoming_webhook_flow( .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) .attach_printable("payment id not received from payments core")?; - let event_type: enums::EventType = payments_response - .status - .foreign_try_into() - .into_report() - .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) - .attach_printable("payment event type mapping failed")?; + let event_type: Option = payments_response.status.foreign_into(); - create_event_and_trigger_outgoing_webhook::( - state, - merchant_account, - event_type, - enums::EventClass::Payments, - None, - payment_id, - enums::EventObjectType::PaymentDetails, - api::OutgoingWebhookContent::PaymentDetails(payments_response), - ) - .await?; + // If event is NOT an UnsupportedEvent, trigger Outgoing Webhook + if let Some(outgoing_event_type) = event_type { + create_event_and_trigger_outgoing_webhook::( + state, + merchant_account, + outgoing_event_type, + enums::EventClass::Payments, + None, + payment_id, + enums::EventObjectType::PaymentDetails, + api::OutgoingWebhookContent::PaymentDetails(payments_response), + ) + .await?; + } } _ => Err(errors::ApiErrorResponse::WebhookProcessingFailure) @@ -213,24 +211,24 @@ pub async fn refunds_incoming_webhook_flow( ) })? }; - let event_type: enums::EventType = updated_refund - .refund_status - .foreign_try_into() - .into_report() - .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) - .attach_printable("refund status to event type mapping failed")?; - let refund_response: api_models::refunds::RefundResponse = updated_refund.foreign_into(); - create_event_and_trigger_outgoing_webhook::( - state, - merchant_account, - event_type, - enums::EventClass::Refunds, - None, - refund_id, - enums::EventObjectType::RefundDetails, - api::OutgoingWebhookContent::RefundDetails(refund_response), - ) - .await?; + let event_type: Option = updated_refund.refund_status.foreign_into(); + + // If event is NOT an UnsupportedEvent, trigger Outgoing Webhook + if let Some(outgoing_event_type) = event_type { + let refund_response: api_models::refunds::RefundResponse = updated_refund.foreign_into(); + create_event_and_trigger_outgoing_webhook::( + state, + merchant_account, + outgoing_event_type, + enums::EventClass::Refunds, + None, + refund_id, + enums::EventObjectType::RefundDetails, + api::OutgoingWebhookContent::RefundDetails(refund_response), + ) + .await?; + } + Ok(()) } @@ -385,12 +383,8 @@ pub async fn disputes_incoming_webhook_flow( ) .await?; let disputes_response = Box::new(dispute_object.clone().foreign_into()); - let event_type: enums::EventType = dispute_object - .dispute_status - .foreign_try_into() - .into_report() - .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) - .attach_printable("failed to map dispute status to event type")?; + let event_type: enums::EventType = dispute_object.dispute_status.foreign_into(); + create_event_and_trigger_outgoing_webhook::( state, merchant_account, @@ -457,24 +451,22 @@ async fn bank_transfer_webhook_flow( .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) .attach_printable("did not receive payment id from payments core response")?; - let event_type: enums::EventType = payments_response - .status - .foreign_try_into() - .into_report() - .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) - .attach_printable("error mapping payments response status to event type")?; + let event_type: Option = payments_response.status.foreign_into(); - create_event_and_trigger_outgoing_webhook::( - state, - merchant_account, - event_type, - enums::EventClass::Payments, - None, - payment_id, - enums::EventObjectType::PaymentDetails, - api::OutgoingWebhookContent::PaymentDetails(payments_response), - ) - .await?; + // If event is NOT an UnsupportedEvent, trigger Outgoing Webhook + if let Some(outgoing_event_type) = event_type { + create_event_and_trigger_outgoing_webhook::( + state, + merchant_account, + outgoing_event_type, + enums::EventClass::Payments, + None, + payment_id, + enums::EventObjectType::PaymentDetails, + api::OutgoingWebhookContent::PaymentDetails(payments_response), + ) + .await?; + } } _ => Err(errors::ApiErrorResponse::WebhookProcessingFailure) diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 6bf55b0888..df8022cfc0 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -185,19 +185,23 @@ impl ForeignFrom for storage_enums::Man } } -impl ForeignTryFrom for storage_enums::EventType { - type Error = errors::ValidationError; - - fn foreign_try_from(value: api_enums::IntentStatus) -> Result { +impl ForeignFrom for Option { + fn foreign_from(value: api_enums::IntentStatus) -> Self { match value { - api_enums::IntentStatus::Succeeded => Ok(Self::PaymentSucceeded), - api_enums::IntentStatus::Failed => Ok(Self::PaymentFailed), - api_enums::IntentStatus::Processing => Ok(Self::PaymentProcessing), + api_enums::IntentStatus::Succeeded => Some(storage_enums::EventType::PaymentSucceeded), + api_enums::IntentStatus::Failed => Some(storage_enums::EventType::PaymentFailed), + api_enums::IntentStatus::Processing => { + Some(storage_enums::EventType::PaymentProcessing) + } api_enums::IntentStatus::RequiresMerchantAction - | api_enums::IntentStatus::RequiresCustomerAction => Ok(Self::ActionRequired), - _ => Err(errors::ValidationError::IncorrectValueProvided { - field_name: "intent_status", - }), + | api_enums::IntentStatus::RequiresCustomerAction => { + Some(storage_enums::EventType::ActionRequired) + } + api_enums::IntentStatus::Cancelled + | api_enums::IntentStatus::RequiresPaymentMethod + | api_enums::IntentStatus::RequiresConfirmation + | api_enums::IntentStatus::RequiresCapture + | api_enums::IntentStatus::PartiallyCaptured => None, } } } @@ -320,32 +324,28 @@ impl ForeignTryFrom for api_enums::Paym } } -impl ForeignTryFrom for storage_enums::EventType { - type Error = errors::ValidationError; - - fn foreign_try_from(value: storage_enums::RefundStatus) -> Result { +impl ForeignFrom for Option { + fn foreign_from(value: storage_enums::RefundStatus) -> Self { match value { - storage_enums::RefundStatus::Success => Ok(Self::RefundSucceeded), - storage_enums::RefundStatus::Failure => Ok(Self::RefundFailed), - _ => Err(errors::ValidationError::IncorrectValueProvided { - field_name: "refund_status", - }), + storage_enums::RefundStatus::Success => Some(storage_enums::EventType::RefundSucceeded), + storage_enums::RefundStatus::Failure => Some(storage_enums::EventType::RefundFailed), + api_enums::RefundStatus::ManualReview + | api_enums::RefundStatus::Pending + | api_enums::RefundStatus::TransactionFailure => None, } } } -impl ForeignTryFrom for storage_enums::EventType { - type Error = errors::ValidationError; - - fn foreign_try_from(value: storage_enums::DisputeStatus) -> Result { +impl ForeignFrom for storage_enums::EventType { + fn foreign_from(value: storage_enums::DisputeStatus) -> Self { match value { - storage_enums::DisputeStatus::DisputeOpened => Ok(Self::DisputeOpened), - storage_enums::DisputeStatus::DisputeExpired => Ok(Self::DisputeExpired), - storage_enums::DisputeStatus::DisputeAccepted => Ok(Self::DisputeAccepted), - storage_enums::DisputeStatus::DisputeCancelled => Ok(Self::DisputeCancelled), - storage_enums::DisputeStatus::DisputeChallenged => Ok(Self::DisputeChallenged), - storage_enums::DisputeStatus::DisputeWon => Ok(Self::DisputeWon), - storage_enums::DisputeStatus::DisputeLost => Ok(Self::DisputeLost), + storage_enums::DisputeStatus::DisputeOpened => Self::DisputeOpened, + storage_enums::DisputeStatus::DisputeExpired => Self::DisputeExpired, + storage_enums::DisputeStatus::DisputeAccepted => Self::DisputeAccepted, + storage_enums::DisputeStatus::DisputeCancelled => Self::DisputeCancelled, + storage_enums::DisputeStatus::DisputeChallenged => Self::DisputeChallenged, + storage_enums::DisputeStatus::DisputeWon => Self::DisputeWon, + storage_enums::DisputeStatus::DisputeLost => Self::DisputeLost, } } } diff --git a/crates/test_utils/tests/connectors/adyen_uk_ui.rs b/crates/test_utils/tests/connectors/adyen_uk_ui.rs index 799bedc8a9..ae71494867 100644 --- a/crates/test_utils/tests/connectors/adyen_uk_ui.rs +++ b/crates/test_utils/tests/connectors/adyen_uk_ui.rs @@ -19,7 +19,7 @@ async fn should_make_adyen_3ds_payment_failed(web_driver: WebDriver) -> Result<( Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/177"))), Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))), Event::Trigger(Trigger::SwitchFrame(By::Name("threeDSIframe"))), - Event::Assert(Assert::Eq(Selector::Title, "Payment Authentication")), + Event::Assert(Assert::IsPresent("AUTHENTICATION DETAILS")), Event::Trigger(Trigger::SendKeys(By::ClassName("input-field"), "password")), Event::Trigger(Trigger::Click(By::Id("buttonSubmit"))), Event::Trigger(Trigger::Sleep(5)), @@ -40,7 +40,7 @@ async fn should_make_adyen_3ds_payment_success( Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/62"))), Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))), Event::Trigger(Trigger::SwitchFrame(By::Name("threeDSIframe"))), - Event::Assert(Assert::Eq(Selector::Title, "Payment Authentication")), + Event::Assert(Assert::IsPresent("AUTHENTICATION DETAILS")), Event::Trigger(Trigger::SendKeys(By::ClassName("input-field"), "password")), Event::Trigger(Trigger::Click(By::Id("buttonSubmit"))), Event::Trigger(Trigger::Sleep(5)), diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 85c6e8565e..03f94b0d81 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -9931,6 +9931,11 @@ "description": "The identifier for the payment", "nullable": true }, + "refund_id": { + "type": "string", + "description": "The identifier for the refund", + "nullable": true + }, "limit": { "type": "integer", "format": "int64", @@ -9974,15 +9979,21 @@ "RefundListResponse": { "type": "object", "required": [ - "size", + "count", + "total_count", "data" ], "properties": { - "size": { + "count": { "type": "integer", "description": "The number of refunds included in the list", "minimum": 0 }, + "total_count": { + "type": "integer", + "format": "int64", + "description": "The total number of refunds in the list" + }, "data": { "type": "array", "items": {