From fc81f90f6168dc6e08cbfacdda0f59e99def07da Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:57:46 +0530 Subject: [PATCH] feat(connector): [Paypal] Unify error code and error message in Paypal (#2354) Co-authored-by: Arjun Karthik --- crates/router/src/connector/paypal.rs | 158 +++++++++++++++++- .../src/connector/paypal/transformers.rs | 18 ++ 2 files changed, 167 insertions(+), 9 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 1c168ba499..1aa1252bdd 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -9,12 +9,12 @@ use masking::{ExposeInterface, PeekInterface, Secret}; use transformers as paypal; use self::transformers::{auth_headers, PaypalAuthResponse, PaypalMeta, PaypalWebhookEventType}; -use super::utils::PaymentsCompleteAuthorizeRequestData; +use super::utils::{ConnectorErrorType, PaymentsCompleteAuthorizeRequestData}; use crate::{ configs::settings, connector::{ utils as connector_utils, - utils::{to_connector_meta, RefundsRequestData}, + utils::{to_connector_meta, ConnectorErrorTypeMapping, RefundsRequestData}, }, consts, core::{ @@ -72,7 +72,7 @@ impl Paypal { event_builder.map(|i| i.set_error_response_body(&response)); router_env::logger::info!(connector_response=?response); - let error_reason = response.details.map(|order_errors| { + let error_reason = response.details.clone().map(|order_errors| { order_errors .iter() .map(|error| { @@ -92,10 +92,24 @@ impl Paypal { }) .collect::() }); + let errors_list = response.details.unwrap_or_default(); + let option_error_code_message = + connector_utils::get_error_code_error_message_based_on_priority( + Self.clone(), + errors_list + .into_iter() + .map(|errors| errors.into()) + .collect(), + ); Ok(ErrorResponse { status_code: res.status_code, - code: response.name, - message: response.message.clone(), + code: option_error_code_message + .clone() + .map(|error_code_message| error_code_message.error_code) + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: option_error_code_message + .map(|error_code_message| error_code_message.error_message) + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), reason: error_reason.or(Some(response.message)), attempt_status: None, connector_transaction_id: None, @@ -224,6 +238,7 @@ impl ConnectorCommon for Paypal { let error_reason = response .details + .clone() .map(|error_details| { error_details .iter() @@ -249,11 +264,25 @@ impl ConnectorCommon for Paypal { .or(Some(err_reason)), None => Some(response.message.to_owned()), }; + let errors_list = response.details.unwrap_or_default(); + let option_error_code_message = + connector_utils::get_error_code_error_message_based_on_priority( + Self.clone(), + errors_list + .into_iter() + .map(|errors| errors.into()) + .collect(), + ); Ok(ErrorResponse { status_code: res.status_code, - code: response.name, - message: response.message.clone(), + code: option_error_code_message + .clone() + .map(|error_code_message| error_code_message.error_code) + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: option_error_code_message + .map(|error_code_message| error_code_message.error_message) + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), reason, attempt_status: None, connector_transaction_id: None, @@ -388,8 +417,8 @@ impl ConnectorIntegration ConnectorErrorType { + match error_code.as_str() { + "CANNOT_BE_NEGATIVE" => ConnectorErrorType::UserError, + "CANNOT_BE_ZERO_OR_NEGATIVE" => ConnectorErrorType::UserError, + "CARD_EXPIRED" => ConnectorErrorType::UserError, + "DECIMAL_PRECISION" => ConnectorErrorType::UserError, + "DUPLICATE_INVOICE_ID" => ConnectorErrorType::UserError, + "INSTRUMENT_DECLINED" => ConnectorErrorType::BusinessError, + "INTERNAL_SERVER_ERROR" => ConnectorErrorType::TechnicalError, + "INVALID_ACCOUNT_STATUS" => ConnectorErrorType::BusinessError, + "INVALID_CURRENCY_CODE" => ConnectorErrorType::UserError, + "INVALID_PARAMETER_SYNTAX" => ConnectorErrorType::UserError, + "INVALID_PARAMETER_VALUE" => ConnectorErrorType::UserError, + "INVALID_RESOURCE_ID" => ConnectorErrorType::UserError, + "INVALID_STRING_LENGTH" => ConnectorErrorType::UserError, + "MISSING_REQUIRED_PARAMETER" => ConnectorErrorType::UserError, + "PAYER_ACCOUNT_LOCKED_OR_CLOSED" => ConnectorErrorType::BusinessError, + "PAYER_ACCOUNT_RESTRICTED" => ConnectorErrorType::BusinessError, + "PAYER_CANNOT_PAY" => ConnectorErrorType::BusinessError, + "PERMISSION_DENIED" => ConnectorErrorType::BusinessError, + "INVALID_ARRAY_MAX_ITEMS" => ConnectorErrorType::UserError, + "INVALID_ARRAY_MIN_ITEMS" => ConnectorErrorType::UserError, + "INVALID_COUNTRY_CODE" => ConnectorErrorType::UserError, + "NOT_SUPPORTED" => ConnectorErrorType::BusinessError, + "PAYPAL_REQUEST_ID_REQUIRED" => ConnectorErrorType::UserError, + "MALFORMED_REQUEST_JSON" => ConnectorErrorType::UserError, + "PERMISSION_DENIED_FOR_DONATION_ITEMS" => ConnectorErrorType::BusinessError, + "MALFORMED_REQUEST" => ConnectorErrorType::TechnicalError, + "AMOUNT_MISMATCH" => ConnectorErrorType::UserError, + "BILLING_ADDRESS_INVALID" => ConnectorErrorType::UserError, + "CITY_REQUIRED" => ConnectorErrorType::UserError, + "DONATION_ITEMS_NOT_SUPPORTED" => ConnectorErrorType::BusinessError, + "DUPLICATE_REFERENCE_ID" => ConnectorErrorType::UserError, + "INVALID_PAYER_ID" => ConnectorErrorType::UserError, + "ITEM_TOTAL_REQUIRED" => ConnectorErrorType::UserError, + "MAX_VALUE_EXCEEDED" => ConnectorErrorType::UserError, + "MISSING_PICKUP_ADDRESS" => ConnectorErrorType::UserError, + "MULTI_CURRENCY_ORDER" => ConnectorErrorType::BusinessError, + "MULTIPLE_ITEM_CATEGORIES" => ConnectorErrorType::UserError, + "MULTIPLE_SHIPPING_ADDRESS_NOT_SUPPORTED" => ConnectorErrorType::UserError, + "MULTIPLE_SHIPPING_TYPE_NOT_SUPPORTED" => ConnectorErrorType::BusinessError, + "PAYEE_ACCOUNT_INVALID" => ConnectorErrorType::UserError, + "PAYEE_ACCOUNT_LOCKED_OR_CLOSED" => ConnectorErrorType::UserError, + "REFERENCE_ID_REQUIRED" => ConnectorErrorType::UserError, + "PAYMENT_SOURCE_CANNOT_BE_USED" => ConnectorErrorType::BusinessError, + "PAYMENT_SOURCE_DECLINED_BY_PROCESSOR" => ConnectorErrorType::BusinessError, + "PAYMENT_SOURCE_INFO_CANNOT_BE_VERIFIED" => ConnectorErrorType::BusinessError, + "POSTAL_CODE_REQUIRED" => ConnectorErrorType::UserError, + "SHIPPING_ADDRESS_INVALID" => ConnectorErrorType::UserError, + "TAX_TOTAL_MISMATCH" => ConnectorErrorType::UserError, + "TAX_TOTAL_REQUIRED" => ConnectorErrorType::UserError, + "UNSUPPORTED_INTENT" => ConnectorErrorType::BusinessError, + "UNSUPPORTED_PAYMENT_INSTRUCTION" => ConnectorErrorType::UserError, + "SHIPPING_TYPE_NOT_SUPPORTED_FOR_CLIENT" => ConnectorErrorType::BusinessError, + "UNSUPPORTED_SHIPPING_TYPE" => ConnectorErrorType::BusinessError, + "PREFERRED_SHIPPING_OPTION_AMOUNT_MISMATCH" => ConnectorErrorType::UserError, + "CARD_CLOSED" => ConnectorErrorType::BusinessError, + "ORDER_CANNOT_BE_SAVED" => ConnectorErrorType::BusinessError, + "SAVE_ORDER_NOT_SUPPORTED" => ConnectorErrorType::BusinessError, + "FIELD_NOT_PATCHABLE" => ConnectorErrorType::UserError, + "AMOUNT_NOT_PATCHABLE" => ConnectorErrorType::UserError, + "INVALID_PATCH_OPERATION" => ConnectorErrorType::UserError, + "PAYEE_ACCOUNT_NOT_SUPPORTED" => ConnectorErrorType::UserError, + "PAYEE_ACCOUNT_NOT_VERIFIED" => ConnectorErrorType::UserError, + "PAYEE_NOT_CONSENTED" => ConnectorErrorType::UserError, + "INVALID_JSON_POINTER_FORMAT" => ConnectorErrorType::BusinessError, + "INVALID_PARAMETER" => ConnectorErrorType::UserError, + "NOT_PATCHABLE" => ConnectorErrorType::BusinessError, + "PATCH_VALUE_REQUIRED" => ConnectorErrorType::UserError, + "PATCH_PATH_REQUIRED" => ConnectorErrorType::UserError, + "REFERENCE_ID_NOT_FOUND" => ConnectorErrorType::UserError, + "SHIPPING_OPTION_NOT_SELECTED" => ConnectorErrorType::UserError, + "SHIPPING_OPTIONS_NOT_SUPPORTED" => ConnectorErrorType::BusinessError, + "MULTIPLE_SHIPPING_OPTION_SELECTED" => ConnectorErrorType::UserError, + "ORDER_ALREADY_COMPLETED" => ConnectorErrorType::BusinessError, + "ACTION_DOES_NOT_MATCH_INTENT" => ConnectorErrorType::BusinessError, + "AGREEMENT_ALREADY_CANCELLED" => ConnectorErrorType::BusinessError, + "BILLING_AGREEMENT_NOT_FOUND" => ConnectorErrorType::BusinessError, + "DOMESTIC_TRANSACTION_REQUIRED" => ConnectorErrorType::BusinessError, + "ORDER_NOT_APPROVED" => ConnectorErrorType::UserError, + "MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED" => ConnectorErrorType::TechnicalError, + "PAYEE_BLOCKED_TRANSACTION" => ConnectorErrorType::BusinessError, + "TRANSACTION_LIMIT_EXCEEDED" => ConnectorErrorType::UserError, + "TRANSACTION_RECEIVING_LIMIT_EXCEEDED" => ConnectorErrorType::BusinessError, + "TRANSACTION_REFUSED" => ConnectorErrorType::TechnicalError, + "ORDER_ALREADY_AUTHORIZED" => ConnectorErrorType::BusinessError, + "AUTH_CAPTURE_NOT_ENABLED" => ConnectorErrorType::BusinessError, + "AMOUNT_CANNOT_BE_SPECIFIED" => ConnectorErrorType::BusinessError, + "AUTHORIZATION_AMOUNT_EXCEEDED" => ConnectorErrorType::UserError, + "AUTHORIZATION_CURRENCY_MISMATCH" => ConnectorErrorType::UserError, + "MAX_AUTHORIZATION_COUNT_EXCEEDED" => ConnectorErrorType::BusinessError, + "ORDER_COMPLETED_OR_VOIDED" => ConnectorErrorType::BusinessError, + "ORDER_EXPIRED" => ConnectorErrorType::BusinessError, + "INVALID_PICKUP_ADDRESS" => ConnectorErrorType::UserError, + "CONSENT_NEEDED" => ConnectorErrorType::UserError, + "COMPLIANCE_VIOLATION" => ConnectorErrorType::BusinessError, + "REDIRECT_PAYER_FOR_ALTERNATE_FUNDING" => ConnectorErrorType::TechnicalError, + "ORDER_ALREADY_CAPTURED" => ConnectorErrorType::UserError, + "TRANSACTION_BLOCKED_BY_PAYEE" => ConnectorErrorType::BusinessError, + "NOT_ENABLED_FOR_CARD_PROCESSING" => ConnectorErrorType::BusinessError, + "PAYEE_NOT_ENABLED_FOR_CARD_PROCESSING" => ConnectorErrorType::BusinessError, + _ => ConnectorErrorType::UnknownError, + } + } +} diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 76ad9c1317..d2d3989a69 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -2173,3 +2173,21 @@ fn get_headers( .to_owned(); Ok(header_value) } + +impl From for utils::ErrorCodeAndMessage { + fn from(error: OrderErrorDetails) -> Self { + Self { + error_code: error.issue.to_string(), + error_message: error.issue.to_string(), + } + } +} + +impl From for utils::ErrorCodeAndMessage { + fn from(error: ErrorDetails) -> Self { + Self { + error_code: error.issue.to_string(), + error_message: error.issue.to_string(), + } + } +}