From 19debb64461ed6da677f6f8ddf34cfe89b82f390 Mon Sep 17 00:00:00 2001 From: sweta-sharma <77436883+swetasharma03@users.noreply.github.com> Date: Thu, 11 Sep 2025 19:22:26 +0530 Subject: [PATCH] feat(connector): [ADYEN] Add support to ideal Mandate Webhook (#9347) --- .../src/connectors/adyen/transformers.rs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs index 7494f45264..4858e70b6f 100644 --- a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs @@ -535,6 +535,8 @@ pub struct AdyenWebhookResponse { refusal_code_raw: Option, // Raw acquirer refusal reason refusal_reason_raw: Option, + recurring_detail_reference: Option>, + recurring_shopper_reference: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -4071,6 +4073,15 @@ pub fn get_webhook_response( txn_amount, )) } else { + let mandate_reference = response + .recurring_detail_reference + .as_ref() + .map(|mandate_id| MandateReference { + connector_mandate_id: Some(mandate_id.clone().expose()), + payment_method_id: response.recurring_shopper_reference.clone(), + mandate_metadata: None, + connector_mandate_request_reference_id: None, + }); let payments_response_data = PaymentsResponseData::TransactionResponse { resource_id: ResponseId::ConnectorTransactionId( response @@ -4078,7 +4089,7 @@ pub fn get_webhook_response( .unwrap_or(response.transaction_id), ), redirection_data: Box::new(None), - mandate_reference: Box::new(None), + mandate_reference: Box::new(mandate_reference), connector_metadata: None, network_txn_id: None, connector_response_reference_id: Some(response.merchant_reference_id), @@ -4884,11 +4895,17 @@ pub struct AdyenAdditionalDataWH { /// Enable recurring details in dashboard to receive this ID, https://docs.adyen.com/online-payments/tokenization/create-and-use-tokens#test-and-go-live #[serde(rename = "recurring.recurringDetailReference")] pub recurring_detail_reference: Option>, + #[serde(rename = "recurring.shopperReference")] + pub recurring_shopper_reference: Option, pub network_tx_reference: Option>, /// [only for cards] Enable raw acquirer from Adyen dashboard to receive this (https://docs.adyen.com/development-resources/raw-acquirer-responses/#search-modal) pub refusal_reason_raw: Option, /// [only for cards] This is only available for Visa and Mastercard pub refusal_code_raw: Option, + #[serde(rename = "shopperEmail")] + pub shopper_email: Option, + #[serde(rename = "shopperReference")] + pub shopper_reference: Option, } #[derive(Debug, Deserialize)] @@ -4916,6 +4933,7 @@ pub enum WebhookEventCode { PrearbitrationWon, PrearbitrationLost, OfferClosed, + RecurringContract, #[cfg(feature = "payouts")] PayoutThirdparty, #[cfg(feature = "payouts")] @@ -4931,7 +4949,9 @@ pub enum WebhookEventCode { pub fn is_transaction_event(event_code: &WebhookEventCode) -> bool { matches!( event_code, - WebhookEventCode::Authorisation | WebhookEventCode::OfferClosed + WebhookEventCode::Authorisation + | WebhookEventCode::OfferClosed + | WebhookEventCode::RecurringContract ) } @@ -5052,6 +5072,13 @@ pub(crate) fn get_adyen_webhook_event( WebhookEventCode::OfferClosed => { api_models::webhooks::IncomingWebhookEvent::PaymentIntentExpired } + WebhookEventCode::RecurringContract => { + if is_success_scenario(is_success) { + api_models::webhooks::IncomingWebhookEvent::PaymentIntentSuccess + } else { + api_models::webhooks::IncomingWebhookEvent::PaymentIntentFailure + } + } #[cfg(feature = "payouts")] WebhookEventCode::PayoutThirdparty => { api_models::webhooks::IncomingWebhookEvent::PayoutCreated @@ -5132,6 +5159,13 @@ impl From for AdyenWebhookResponse { AdyenWebhookStatus::AuthorisationFailed } } + WebhookEventCode::RecurringContract => { + if is_success_scenario(notif.success) { + AdyenWebhookStatus::Authorised + } else { + AdyenWebhookStatus::AuthorisationFailed + } + } WebhookEventCode::Cancellation => { if is_success_scenario(notif.success) { AdyenWebhookStatus::Cancelled @@ -5184,6 +5218,8 @@ impl From for AdyenWebhookResponse { event_code: notif.event_code, refusal_code_raw: notif.additional_data.refusal_code_raw, refusal_reason_raw: notif.additional_data.refusal_reason_raw, + recurring_detail_reference: notif.additional_data.recurring_detail_reference, + recurring_shopper_reference: notif.additional_data.recurring_shopper_reference, } } }