From 733a560146bb06e51fa4ee7ed9b6d1d3d9eddf12 Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Tue, 12 Mar 2024 19:04:40 +0530 Subject: [PATCH] refactor: [Checkout] change payment and webhooks API contract (#4023) --- crates/router/src/connector/checkout.rs | 61 +++++++----- .../src/connector/checkout/transformers.rs | 92 ++++++++++++++++--- 2 files changed, 117 insertions(+), 36 deletions(-) diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs index a21956b67d..30be1315e1 100644 --- a/crates/router/src/connector/checkout.rs +++ b/crates/router/src/connector/checkout.rs @@ -1242,30 +1242,43 @@ impl api::IncomingWebhook for Checkout { .body .parse_struct("CheckoutWebhookBody") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; - - if checkout::is_chargeback_event(&details.transaction_type) { - return Ok(api_models::webhooks::ObjectReferenceId::PaymentId( - api_models::payments::PaymentIdType::ConnectorTransactionId( - details - .data - .payment_id - .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?, - ), - )); - } - if checkout::is_refund_event(&details.transaction_type) { - return Ok(api_models::webhooks::ObjectReferenceId::RefundId( - api_models::webhooks::RefundIdType::ConnectorRefundId( - details - .data - .action_id - .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?, - ), - )); - } - Ok(api_models::webhooks::ObjectReferenceId::PaymentId( - api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.id), - )) + let ref_id: api_models::webhooks::ObjectReferenceId = + if checkout::is_chargeback_event(&details.transaction_type) { + let reference = match details.data.reference { + Some(reference) => { + api_models::payments::PaymentIdType::PaymentAttemptId(reference) + } + None => api_models::payments::PaymentIdType::ConnectorTransactionId( + details + .data + .payment_id + .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?, + ), + }; + api_models::webhooks::ObjectReferenceId::PaymentId(reference) + } else if checkout::is_refund_event(&details.transaction_type) { + let refund_reference = match details.data.reference { + Some(reference) => api_models::webhooks::RefundIdType::RefundId(reference), + None => api_models::webhooks::RefundIdType::ConnectorRefundId( + details + .data + .action_id + .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?, + ), + }; + api_models::webhooks::ObjectReferenceId::RefundId(refund_reference) + } else { + let reference_id = match details.data.reference { + Some(reference) => { + api_models::payments::PaymentIdType::PaymentAttemptId(reference) + } + None => { + api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.id) + } + }; + api_models::webhooks::ObjectReferenceId::PaymentId(reference_id) + }; + Ok(ref_id) } fn get_webhook_event_type( diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 4c03299298..5acf2324f2 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -242,6 +242,7 @@ pub struct PaymentsRequest { pub return_url: ReturnUrl, pub capture: bool, pub reference: String, + pub metadata: Option>, } #[derive(Debug, Serialize, Deserialize)] @@ -428,6 +429,7 @@ impl TryFrom<&CheckoutRouterData<&types::PaymentsAuthorizeRouterData>> for Payme let connector_auth = &item.router_data.connector_auth_type; let auth_type: CheckoutAuthType = connector_auth.try_into()?; let processing_channel_id = auth_type.processing_channel_id; + let metadata = item.router_data.request.metadata.clone(); Ok(Self { source: source_var, amount: item.amount.to_owned(), @@ -437,6 +439,7 @@ impl TryFrom<&CheckoutRouterData<&types::PaymentsAuthorizeRouterData>> for Payme return_url, capture, reference: item.router_data.connector_request_reference_id.clone(), + metadata, }) } } @@ -450,6 +453,16 @@ pub enum CheckoutPaymentStatus { CardVerified, Declined, Captured, + #[serde(rename = "Retry Scheduled")] + RetryScheduled, + Voided, + #[serde(rename = "Partially Captured")] + PartiallyCaptured, + #[serde(rename = "Partially Refunded")] + PartiallyRefunded, + Refunded, + Canceled, + Expired, } impl TryFrom for CheckoutPaymentStatus { @@ -460,7 +473,14 @@ impl TryFrom for CheckoutPaymentStatus { CheckoutWebhookEventType::PaymentCaptured => Ok(Self::Captured), CheckoutWebhookEventType::PaymentDeclined => Ok(Self::Declined), CheckoutWebhookEventType::AuthenticationStarted - | CheckoutWebhookEventType::AuthenticationApproved => Ok(Self::Pending), + | CheckoutWebhookEventType::AuthenticationApproved + | CheckoutWebhookEventType::AuthenticationAttempted => Ok(Self::Pending), + CheckoutWebhookEventType::AuthenticationExpired + | CheckoutWebhookEventType::AuthenticationFailed + | CheckoutWebhookEventType::PaymentAuthenticationFailed + | CheckoutWebhookEventType::PaymentCaptureDeclined => Ok(Self::Declined), + CheckoutWebhookEventType::PaymentCanceled => Ok(Self::Canceled), + CheckoutWebhookEventType::PaymentVoided => Ok(Self::Voided), CheckoutWebhookEventType::PaymentRefunded | CheckoutWebhookEventType::PaymentRefundDeclined | CheckoutWebhookEventType::DisputeReceived @@ -494,10 +514,18 @@ impl ForeignFrom<(CheckoutPaymentStatus, Option)> for enum Self::Authorized } } - CheckoutPaymentStatus::Captured => Self::Charged, - CheckoutPaymentStatus::Declined => Self::Failure, + CheckoutPaymentStatus::Captured + | CheckoutPaymentStatus::PartiallyRefunded + | CheckoutPaymentStatus::Refunded => Self::Charged, + CheckoutPaymentStatus::PartiallyCaptured => Self::PartialCharged, + CheckoutPaymentStatus::Declined + | CheckoutPaymentStatus::Expired + | CheckoutPaymentStatus::Canceled => Self::Failure, CheckoutPaymentStatus::Pending => Self::AuthenticationPending, - CheckoutPaymentStatus::CardVerified => Self::Pending, + CheckoutPaymentStatus::CardVerified | CheckoutPaymentStatus::RetryScheduled => { + Self::Pending + } + CheckoutPaymentStatus::Voided => Self::Voided, } } } @@ -514,10 +542,18 @@ impl ForeignFrom<(CheckoutPaymentStatus, CheckoutPaymentIntent)> for enums::Atte Self::Authorized } } - CheckoutPaymentStatus::Captured => Self::Charged, - CheckoutPaymentStatus::Declined => Self::Failure, + CheckoutPaymentStatus::Captured + | CheckoutPaymentStatus::PartiallyRefunded + | CheckoutPaymentStatus::Refunded => Self::Charged, + CheckoutPaymentStatus::PartiallyCaptured => Self::PartialCharged, + CheckoutPaymentStatus::Declined + | CheckoutPaymentStatus::Expired + | CheckoutPaymentStatus::Canceled => Self::Failure, CheckoutPaymentStatus::Pending => Self::AuthenticationPending, - CheckoutPaymentStatus::CardVerified => Self::Pending, + CheckoutPaymentStatus::CardVerified | CheckoutPaymentStatus::RetryScheduled => { + Self::Pending + } + CheckoutPaymentStatus::Voided => Self::Voided, } } } @@ -537,10 +573,18 @@ impl ForeignFrom<(CheckoutPaymentStatus, Option)> for enums::AttemptSt Self::Authorized } } - CheckoutPaymentStatus::Captured => Self::Charged, - CheckoutPaymentStatus::Declined => Self::Failure, + CheckoutPaymentStatus::Captured + | CheckoutPaymentStatus::PartiallyRefunded + | CheckoutPaymentStatus::Refunded => Self::Charged, + CheckoutPaymentStatus::PartiallyCaptured => Self::PartialCharged, + CheckoutPaymentStatus::Declined + | CheckoutPaymentStatus::Expired + | CheckoutPaymentStatus::Canceled => Self::Failure, CheckoutPaymentStatus::Pending => Self::AuthenticationPending, - CheckoutPaymentStatus::CardVerified => Self::Pending, + CheckoutPaymentStatus::CardVerified | CheckoutPaymentStatus::RetryScheduled => { + Self::Pending + } + CheckoutPaymentStatus::Voided => Self::Voided, } } } @@ -559,6 +603,7 @@ pub struct Links { pub struct PaymentsResponse { id: String, amount: Option, + currency: Option, action_id: Option, status: CheckoutPaymentStatus, #[serde(rename = "_links")] @@ -567,6 +612,8 @@ pub struct PaymentsResponse { reference: Option, response_code: Option, response_summary: Option, + approved: Option, + processed_on: Option, } #[derive(Debug, Deserialize, Serialize)] @@ -1132,11 +1179,18 @@ pub fn is_chargeback_event(event_code: &CheckoutWebhookEventType) -> bool { pub enum CheckoutWebhookEventType { AuthenticationStarted, AuthenticationApproved, + AuthenticationAttempted, + AuthenticationExpired, + AuthenticationFailed, PaymentApproved, PaymentCaptured, PaymentDeclined, PaymentRefunded, PaymentRefundDeclined, + PaymentAuthenticationFailed, + PaymentCanceled, + PaymentCaptureDeclined, + PaymentVoided, DisputeReceived, DisputeExpired, DisputeAccepted, @@ -1169,6 +1223,8 @@ pub struct CheckoutWebhookData { pub response_code: Option, pub response_summary: Option, pub currency: String, + pub processed_on: Option, + pub approved: Option, } #[derive(Debug, Deserialize)] @@ -1220,13 +1276,22 @@ pub enum CheckoutDisputeTransactionType { impl From for api::IncomingWebhookEvent { fn from(transaction_type: CheckoutWebhookEventType) -> Self { match transaction_type { - CheckoutWebhookEventType::AuthenticationStarted => Self::EventNotSupported, - CheckoutWebhookEventType::AuthenticationApproved => Self::EventNotSupported, + CheckoutWebhookEventType::AuthenticationStarted + | CheckoutWebhookEventType::AuthenticationApproved + | CheckoutWebhookEventType::AuthenticationAttempted => Self::EventNotSupported, + CheckoutWebhookEventType::AuthenticationExpired + | CheckoutWebhookEventType::AuthenticationFailed + | CheckoutWebhookEventType::PaymentAuthenticationFailed => { + Self::PaymentIntentAuthorizationFailure + } CheckoutWebhookEventType::PaymentApproved => Self::EventNotSupported, CheckoutWebhookEventType::PaymentCaptured => Self::PaymentIntentSuccess, CheckoutWebhookEventType::PaymentDeclined => Self::PaymentIntentFailure, CheckoutWebhookEventType::PaymentRefunded => Self::RefundSuccess, CheckoutWebhookEventType::PaymentRefundDeclined => Self::RefundFailure, + CheckoutWebhookEventType::PaymentCanceled => Self::PaymentIntentCancelFailure, + CheckoutWebhookEventType::PaymentCaptureDeclined => Self::PaymentIntentCaptureFailure, + CheckoutWebhookEventType::PaymentVoided => Self::PaymentIntentCancelled, CheckoutWebhookEventType::DisputeReceived | CheckoutWebhookEventType::DisputeEvidenceRequired => Self::DisputeOpened, CheckoutWebhookEventType::DisputeExpired => Self::DisputeExpired, @@ -1329,6 +1394,9 @@ impl TryFrom<&api::IncomingWebhookRequestDetails<'_>> for PaymentsResponse { response_code: data.response_code, response_summary: data.response_summary, action_id: data.action_id, + currency: Some(data.currency), + processed_on: data.processed_on, + approved: data.approved, }; Ok(psync_struct)