mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(connector): [CYBERSOURCE] Refactor cybersource (#3215)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -446,6 +446,27 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
|
|||||||
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
self.build_error_response(res)
|
self.build_error_response(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_5xx_error_response(
|
||||||
|
&self,
|
||||||
|
res: types::Response,
|
||||||
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
|
let response: cybersource::CybersourceServerErrorResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("CybersourceServerErrorResponse")
|
||||||
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||||
|
|
||||||
|
Ok(types::ErrorResponse {
|
||||||
|
status_code: res.status_code,
|
||||||
|
reason: response.status.clone(),
|
||||||
|
code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()),
|
||||||
|
message: response
|
||||||
|
.message
|
||||||
|
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
|
||||||
|
attempt_status: None,
|
||||||
|
connector_transaction_id: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
|
impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
|
||||||
@ -606,6 +627,33 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
|
|||||||
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
self.build_error_response(res)
|
self.build_error_response(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_5xx_error_response(
|
||||||
|
&self,
|
||||||
|
res: types::Response,
|
||||||
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
|
let response: cybersource::CybersourceServerErrorResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("CybersourceServerErrorResponse")
|
||||||
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||||
|
let attempt_status = match response.reason {
|
||||||
|
Some(reason) => match reason {
|
||||||
|
transformers::Reason::SystemError => Some(enums::AttemptStatus::Failure),
|
||||||
|
transformers::Reason::ServerTimeout | transformers::Reason::ServiceTimeout => None,
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
Ok(types::ErrorResponse {
|
||||||
|
status_code: res.status_code,
|
||||||
|
reason: response.status.clone(),
|
||||||
|
code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()),
|
||||||
|
message: response
|
||||||
|
.message
|
||||||
|
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
|
||||||
|
attempt_status,
|
||||||
|
connector_transaction_id: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
|
impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
|
||||||
@ -626,9 +674,8 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
|
|||||||
) -> CustomResult<String, errors::ConnectorError> {
|
) -> CustomResult<String, errors::ConnectorError> {
|
||||||
let connector_payment_id = req.request.connector_transaction_id.clone();
|
let connector_payment_id = req.request.connector_transaction_id.clone();
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"{}pts/v2/payments/{}/voids",
|
"{}pts/v2/payments/{connector_payment_id}/reversals",
|
||||||
self.base_url(connectors),
|
self.base_url(connectors)
|
||||||
connector_payment_id
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,10 +685,26 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
|
|||||||
|
|
||||||
fn get_request_body(
|
fn get_request_body(
|
||||||
&self,
|
&self,
|
||||||
_req: &types::PaymentsCancelRouterData,
|
req: &types::PaymentsCancelRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
Ok(RequestContent::Json(Box::new(serde_json::json!({}))))
|
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
||||||
|
&self.get_currency_unit(),
|
||||||
|
req.request
|
||||||
|
.currency
|
||||||
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "Currency",
|
||||||
|
})?,
|
||||||
|
req.request
|
||||||
|
.amount
|
||||||
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "Amount",
|
||||||
|
})?,
|
||||||
|
req,
|
||||||
|
))?;
|
||||||
|
let connector_req = cybersource::CybersourceVoidRequest::try_from(&connector_router_data)?;
|
||||||
|
|
||||||
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_request(
|
fn build_request(
|
||||||
@ -682,6 +745,27 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
|
|||||||
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
self.build_error_response(res)
|
self.build_error_response(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_5xx_error_response(
|
||||||
|
&self,
|
||||||
|
res: types::Response,
|
||||||
|
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
|
||||||
|
let response: cybersource::CybersourceServerErrorResponse = res
|
||||||
|
.response
|
||||||
|
.parse_struct("CybersourceServerErrorResponse")
|
||||||
|
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||||
|
|
||||||
|
Ok(types::ErrorResponse {
|
||||||
|
status_code: res.status_code,
|
||||||
|
reason: response.status.clone(),
|
||||||
|
code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()),
|
||||||
|
message: response
|
||||||
|
.message
|
||||||
|
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
|
||||||
|
attempt_status: None,
|
||||||
|
connector_transaction_id: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl api::Refund for Cybersource {}
|
impl api::Refund for Cybersource {}
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use api_models::payments;
|
use api_models::payments;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use common_utils::pii;
|
use common_utils::pii;
|
||||||
use masking::{PeekInterface, Secret};
|
use masking::{PeekInterface, Secret};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connector::utils::{
|
connector::utils::{
|
||||||
@ -134,6 +137,8 @@ pub struct CybersourcePaymentsRequest {
|
|||||||
payment_information: PaymentInformation,
|
payment_information: PaymentInformation,
|
||||||
order_information: OrderInformationWithBill,
|
order_information: OrderInformationWithBill,
|
||||||
client_reference_information: ClientReferenceInformation,
|
client_reference_information: ClientReferenceInformation,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
merchant_defined_information: Option<Vec<MerchantDefinedInformation>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
@ -148,6 +153,13 @@ pub struct ProcessingInformation {
|
|||||||
payment_solution: Option<String>,
|
payment_solution: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct MerchantDefinedInformation {
|
||||||
|
key: u8,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
pub enum CybersourceActionsList {
|
pub enum CybersourceActionsList {
|
||||||
@ -218,6 +230,19 @@ pub struct TokenizedCard {
|
|||||||
transaction_type: TransactionType,
|
transaction_type: TransactionType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ApplePayTokenizedCard {
|
||||||
|
transaction_type: TransactionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ApplePayTokenPaymentInformation {
|
||||||
|
fluid_data: FluidData,
|
||||||
|
tokenized_card: ApplePayTokenizedCard,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ApplePayPaymentInformation {
|
pub struct ApplePayPaymentInformation {
|
||||||
@ -242,6 +267,7 @@ pub enum PaymentInformation {
|
|||||||
Cards(CardPaymentInformation),
|
Cards(CardPaymentInformation),
|
||||||
GooglePay(GooglePayPaymentInformation),
|
GooglePay(GooglePayPaymentInformation),
|
||||||
ApplePay(ApplePayPaymentInformation),
|
ApplePay(ApplePayPaymentInformation),
|
||||||
|
ApplePayToken(ApplePayTokenPaymentInformation),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -441,6 +467,23 @@ fn build_bill_to(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ForeignFrom<Value> for Vec<MerchantDefinedInformation> {
|
||||||
|
fn foreign_from(metadata: Value) -> Self {
|
||||||
|
let hashmap: HashMap<String, Value> =
|
||||||
|
serde_json::from_str(&metadata.to_string()).unwrap_or(HashMap::new());
|
||||||
|
let mut vector: Self = Self::new();
|
||||||
|
let mut iter = 1;
|
||||||
|
for (key, value) in hashmap {
|
||||||
|
vector.push(MerchantDefinedInformation {
|
||||||
|
key: iter,
|
||||||
|
value: format!("{key}={value}"),
|
||||||
|
});
|
||||||
|
iter += 1;
|
||||||
|
}
|
||||||
|
vector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl
|
impl
|
||||||
TryFrom<(
|
TryFrom<(
|
||||||
&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>,
|
&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>,
|
||||||
@ -491,15 +534,19 @@ impl
|
|||||||
card,
|
card,
|
||||||
instrument_identifier,
|
instrument_identifier,
|
||||||
});
|
});
|
||||||
|
|
||||||
let processing_information = ProcessingInformation::from((item, None));
|
let processing_information = ProcessingInformation::from((item, None));
|
||||||
let client_reference_information = ClientReferenceInformation::from(item);
|
let client_reference_information = ClientReferenceInformation::from(item);
|
||||||
|
let merchant_defined_information =
|
||||||
|
item.router_data.request.metadata.clone().map(|metadata| {
|
||||||
|
Vec::<MerchantDefinedInformation>::foreign_from(metadata.peek().to_owned())
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
processing_information,
|
processing_information,
|
||||||
payment_information,
|
payment_information,
|
||||||
order_information,
|
order_information,
|
||||||
client_reference_information,
|
client_reference_information,
|
||||||
|
merchant_defined_information,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,7 +572,6 @@ impl
|
|||||||
let client_reference_information = ClientReferenceInformation::from(item);
|
let client_reference_information = ClientReferenceInformation::from(item);
|
||||||
let expiration_month = apple_pay_data.get_expiry_month()?;
|
let expiration_month = apple_pay_data.get_expiry_month()?;
|
||||||
let expiration_year = apple_pay_data.get_four_digit_expiry_year()?;
|
let expiration_year = apple_pay_data.get_four_digit_expiry_year()?;
|
||||||
|
|
||||||
let payment_information = PaymentInformation::ApplePay(ApplePayPaymentInformation {
|
let payment_information = PaymentInformation::ApplePay(ApplePayPaymentInformation {
|
||||||
tokenized_card: TokenizedCard {
|
tokenized_card: TokenizedCard {
|
||||||
number: apple_pay_data.application_primary_account_number,
|
number: apple_pay_data.application_primary_account_number,
|
||||||
@ -535,12 +581,17 @@ impl
|
|||||||
expiration_month,
|
expiration_month,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
let merchant_defined_information =
|
||||||
|
item.router_data.request.metadata.clone().map(|metadata| {
|
||||||
|
Vec::<MerchantDefinedInformation>::foreign_from(metadata.peek().to_owned())
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
processing_information,
|
processing_information,
|
||||||
payment_information,
|
payment_information,
|
||||||
order_information,
|
order_information,
|
||||||
client_reference_information,
|
client_reference_information,
|
||||||
|
merchant_defined_information,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -569,16 +620,20 @@ impl
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let processing_information =
|
let processing_information =
|
||||||
ProcessingInformation::from((item, Some(PaymentSolution::GooglePay)));
|
ProcessingInformation::from((item, Some(PaymentSolution::GooglePay)));
|
||||||
let client_reference_information = ClientReferenceInformation::from(item);
|
let client_reference_information = ClientReferenceInformation::from(item);
|
||||||
|
let merchant_defined_information =
|
||||||
|
item.router_data.request.metadata.clone().map(|metadata| {
|
||||||
|
Vec::<MerchantDefinedInformation>::foreign_from(metadata.peek().to_owned())
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
processing_information,
|
processing_information,
|
||||||
payment_information,
|
payment_information,
|
||||||
order_information,
|
order_information,
|
||||||
client_reference_information,
|
client_reference_information,
|
||||||
|
merchant_defined_information,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,14 +648,50 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>>
|
|||||||
match item.router_data.request.payment_method_data.clone() {
|
match item.router_data.request.payment_method_data.clone() {
|
||||||
payments::PaymentMethodData::Card(ccard) => Self::try_from((item, ccard)),
|
payments::PaymentMethodData::Card(ccard) => Self::try_from((item, ccard)),
|
||||||
payments::PaymentMethodData::Wallet(wallet_data) => match wallet_data {
|
payments::PaymentMethodData::Wallet(wallet_data) => match wallet_data {
|
||||||
payments::WalletData::ApplePay(_) => {
|
payments::WalletData::ApplePay(apple_pay_data) => {
|
||||||
let payment_method_token = item.router_data.get_payment_method_token()?;
|
match item.router_data.payment_method_token.clone() {
|
||||||
match payment_method_token {
|
Some(payment_method_token) => match payment_method_token {
|
||||||
types::PaymentMethodToken::ApplePayDecrypt(decrypt_data) => {
|
types::PaymentMethodToken::ApplePayDecrypt(decrypt_data) => {
|
||||||
Self::try_from((item, decrypt_data))
|
Self::try_from((item, decrypt_data))
|
||||||
}
|
}
|
||||||
types::PaymentMethodToken::Token(_) => {
|
types::PaymentMethodToken::Token(_) => {
|
||||||
Err(errors::ConnectorError::InvalidWalletToken)?
|
Err(errors::ConnectorError::InvalidWalletToken)?
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let email = item.router_data.request.get_email()?;
|
||||||
|
let bill_to = build_bill_to(item.router_data.get_billing()?, email)?;
|
||||||
|
let order_information = OrderInformationWithBill::from((item, bill_to));
|
||||||
|
let processing_information = ProcessingInformation::from((
|
||||||
|
item,
|
||||||
|
Some(PaymentSolution::ApplePay),
|
||||||
|
));
|
||||||
|
let client_reference_information =
|
||||||
|
ClientReferenceInformation::from(item);
|
||||||
|
let payment_information = PaymentInformation::ApplePayToken(
|
||||||
|
ApplePayTokenPaymentInformation {
|
||||||
|
fluid_data: FluidData {
|
||||||
|
value: Secret::from(apple_pay_data.payment_data),
|
||||||
|
},
|
||||||
|
tokenized_card: ApplePayTokenizedCard {
|
||||||
|
transaction_type: TransactionType::ApplePay,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let merchant_defined_information =
|
||||||
|
item.router_data.request.metadata.clone().map(|metadata| {
|
||||||
|
Vec::<MerchantDefinedInformation>::foreign_from(
|
||||||
|
metadata.peek().to_owned(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
processing_information,
|
||||||
|
payment_information,
|
||||||
|
order_information,
|
||||||
|
client_reference_information,
|
||||||
|
merchant_defined_information,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -737,6 +828,51 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsIncrementalAuthorizationRout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CybersourceVoidRequest {
|
||||||
|
client_reference_information: ClientReferenceInformation,
|
||||||
|
reversal_information: ReversalInformation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ReversalInformation {
|
||||||
|
amount_details: Amount,
|
||||||
|
reason: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&CybersourceRouterData<&types::PaymentsCancelRouterData>> for CybersourceVoidRequest {
|
||||||
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
|
fn try_from(
|
||||||
|
value: &CybersourceRouterData<&types::PaymentsCancelRouterData>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
client_reference_information: ClientReferenceInformation {
|
||||||
|
code: Some(value.router_data.connector_request_reference_id.clone()),
|
||||||
|
},
|
||||||
|
reversal_information: ReversalInformation {
|
||||||
|
amount_details: Amount {
|
||||||
|
total_amount: value.amount.to_owned(),
|
||||||
|
currency: value.router_data.request.currency.ok_or(
|
||||||
|
errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "Currency",
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
},
|
||||||
|
reason: value
|
||||||
|
.router_data
|
||||||
|
.request
|
||||||
|
.cancellation_reason
|
||||||
|
.clone()
|
||||||
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "Cancellation Reason",
|
||||||
|
})?,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CybersourceAuthType {
|
pub struct CybersourceAuthType {
|
||||||
pub(super) api_key: Secret<String>,
|
pub(super) api_key: Secret<String>,
|
||||||
pub(super) merchant_account: Secret<String>,
|
pub(super) merchant_account: Secret<String>,
|
||||||
@ -1079,9 +1215,21 @@ impl<F>
|
|||||||
..item.data
|
..item.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
CybersourcePaymentsResponse::ErrorInformation(ref error_response) => {
|
CybersourcePaymentsResponse::ErrorInformation(error_response) => Ok(Self {
|
||||||
Ok(Self::from((&error_response.clone(), item)))
|
response: Err(types::ErrorResponse {
|
||||||
}
|
code: consts::NO_ERROR_CODE.to_string(),
|
||||||
|
message: error_response
|
||||||
|
.error_information
|
||||||
|
.message
|
||||||
|
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
|
||||||
|
reason: error_response.error_information.reason,
|
||||||
|
status_code: item.http_code,
|
||||||
|
attempt_status: None,
|
||||||
|
connector_transaction_id: Some(error_response.id.clone()),
|
||||||
|
}),
|
||||||
|
status: enums::AttemptStatus::Failure,
|
||||||
|
..item.data
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1496,6 +1644,22 @@ pub struct CybersourceStandardErrorResponse {
|
|||||||
pub details: Option<Vec<Details>>,
|
pub details: Option<Vec<Details>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CybersourceServerErrorResponse {
|
||||||
|
pub status: Option<String>,
|
||||||
|
pub message: Option<String>,
|
||||||
|
pub reason: Option<Reason>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum Reason {
|
||||||
|
SystemError,
|
||||||
|
ServerTimeout,
|
||||||
|
ServiceTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct CybersourceAuthenticationErrorResponse {
|
pub struct CybersourceAuthenticationErrorResponse {
|
||||||
pub response: AuthenticationErrorInformation,
|
pub response: AuthenticationErrorInformation,
|
||||||
|
|||||||
Reference in New Issue
Block a user