mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 17:19:15 +08:00
refactor: raise appropriate errors instead of ValidateError (#71)
This commit is contained in:
@ -4,21 +4,24 @@ use crate::core::errors::ApiErrorResponse;
|
|||||||
#[derive(Debug, router_derive::ApiError)]
|
#[derive(Debug, router_derive::ApiError)]
|
||||||
#[error(error_type_enum = StripeErrorType)]
|
#[error(error_type_enum = StripeErrorType)]
|
||||||
pub(crate) enum ErrorCode {
|
pub(crate) enum ErrorCode {
|
||||||
|
/*
|
||||||
|
"error": {
|
||||||
|
"message": "Invalid API Key provided: sk_jkjgs****nlgs",
|
||||||
|
"type": "invalid_request_error"
|
||||||
|
}
|
||||||
|
*/
|
||||||
#[error(
|
#[error(
|
||||||
error_type = StripeErrorType::InvalidRequestError, code = "IR_01",
|
error_type = StripeErrorType::InvalidRequestError, code = "IR_01",
|
||||||
message = "Invalid API Key provided"
|
message = "Invalid API Key provided"
|
||||||
)]
|
)]
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
/*
|
|
||||||
"error": {
|
|
||||||
"message": "Invalid API Key provided: sk_jkjgs****nlgs",
|
|
||||||
"type": "invalid_request_error"
|
|
||||||
} */
|
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_02", message = "Unrecognized request URL.")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_02", message = "Unrecognized request URL.")]
|
||||||
InvalidRequestUrl,
|
InvalidRequestUrl,
|
||||||
|
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "parameter_missing", message = "Missing required param: {field_name}.")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "parameter_missing", message = "Missing required param: {field_name}.")]
|
||||||
ParameterMissing { field_name: String, param: String },
|
ParameterMissing { field_name: String, param: String },
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
error_type = StripeErrorType::InvalidRequestError, code = "parameter_unknown",
|
error_type = StripeErrorType::InvalidRequestError, code = "parameter_unknown",
|
||||||
message = "{field_name} contains invalid data. Expected format is {expected_format}."
|
message = "{field_name} contains invalid data. Expected format is {expected_format}."
|
||||||
@ -81,8 +84,10 @@ pub(crate) enum ErrorCode {
|
|||||||
|
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate merchant account")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate merchant account")]
|
||||||
DuplicateMerchantAccount,
|
DuplicateMerchantAccount,
|
||||||
|
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate merchant_connector_account")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate merchant_connector_account")]
|
||||||
DuplicateMerchantConnectorAccount,
|
DuplicateMerchantConnectorAccount,
|
||||||
|
|
||||||
#[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate payment method")]
|
#[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate payment method")]
|
||||||
DuplicatePaymentMethod,
|
DuplicatePaymentMethod,
|
||||||
|
|
||||||
@ -96,11 +101,17 @@ pub(crate) enum ErrorCode {
|
|||||||
PaymentIntentInvalidParameter { param: String },
|
PaymentIntentInvalidParameter { param: String },
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
error_type = StripeErrorType::InvalidRequestError, code = "IR-05",
|
error_type = StripeErrorType::InvalidRequestError, code = "IR_05",
|
||||||
message = "{message}"
|
message = "{message}"
|
||||||
)]
|
)]
|
||||||
InvalidRequestData { message: String },
|
InvalidRequestData { message: String },
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
error_type = StripeErrorType::InvalidRequestError, code = "IR_10",
|
||||||
|
message = "{message}"
|
||||||
|
)]
|
||||||
|
PreconditionFailed { message: String },
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
error_type = StripeErrorType::InvalidRequestError, code = "",
|
error_type = StripeErrorType::InvalidRequestError, code = "",
|
||||||
message = "The payment has not succeeded yet"
|
message = "The payment has not succeeded yet"
|
||||||
@ -205,17 +216,13 @@ pub(crate) enum ErrorCode {
|
|||||||
// ParameterInvalidInteger,
|
// ParameterInvalidInteger,
|
||||||
// ParameterInvalidStringBlank,
|
// ParameterInvalidStringBlank,
|
||||||
// ParameterInvalidStringEmpty,
|
// ParameterInvalidStringEmpty,
|
||||||
|
|
||||||
// ParametersExclusive,
|
// ParametersExclusive,
|
||||||
|
|
||||||
// PaymentIntentActionRequired,
|
// PaymentIntentActionRequired,
|
||||||
|
|
||||||
// PaymentIntentIncompatiblePaymentMethod,
|
// PaymentIntentIncompatiblePaymentMethod,
|
||||||
// PaymentIntentInvalidParameter,
|
// PaymentIntentInvalidParameter,
|
||||||
// PaymentIntentKonbiniRejectedConfirmationNumber,
|
// PaymentIntentKonbiniRejectedConfirmationNumber,
|
||||||
// PaymentIntentMandateInvalid,
|
// PaymentIntentMandateInvalid,
|
||||||
// PaymentIntentPaymentAttemptExpired,
|
// PaymentIntentPaymentAttemptExpired,
|
||||||
|
|
||||||
// PaymentIntentUnexpectedState,
|
// PaymentIntentUnexpectedState,
|
||||||
// PaymentMethodBankAccountAlreadyVerified,
|
// PaymentMethodBankAccountAlreadyVerified,
|
||||||
// PaymentMethodBankAccountBlocked,
|
// PaymentMethodBankAccountBlocked,
|
||||||
@ -263,7 +270,6 @@ pub(crate) enum ErrorCode {
|
|||||||
// TerminalLocationCountryUnsupported,
|
// TerminalLocationCountryUnsupported,
|
||||||
// TestmodeChargesOnly,
|
// TestmodeChargesOnly,
|
||||||
// TlsVersionUnsupported,
|
// TlsVersionUnsupported,
|
||||||
// ,
|
|
||||||
// TokenInUse,
|
// TokenInUse,
|
||||||
// TransferSourceBalanceParametersMismatch,
|
// TransferSourceBalanceParametersMismatch,
|
||||||
// TransfersNotAllowed,
|
// TransfersNotAllowed,
|
||||||
@ -299,7 +305,7 @@ impl From<ApiErrorResponse> for ErrorCode {
|
|||||||
field_name: field_name.to_owned(),
|
field_name: field_name.to_owned(),
|
||||||
param: field_name,
|
param: field_name,
|
||||||
},
|
},
|
||||||
// parameter unknown, invalid request error // actually if we type worng values in addrees we get this error. Stripe throws parameter unknown. I don't know if stripe is validating email and stuff
|
// parameter unknown, invalid request error // actually if we type wrong values in address we get this error. Stripe throws parameter unknown. I don't know if stripe is validating email and stuff
|
||||||
ApiErrorResponse::InvalidDataFormat {
|
ApiErrorResponse::InvalidDataFormat {
|
||||||
field_name,
|
field_name,
|
||||||
expected_format,
|
expected_format,
|
||||||
@ -319,7 +325,7 @@ impl From<ApiErrorResponse> for ErrorCode {
|
|||||||
ApiErrorResponse::PaymentCaptureFailed { data } => {
|
ApiErrorResponse::PaymentCaptureFailed { data } => {
|
||||||
ErrorCode::PaymentIntentPaymentAttemptFailed { data }
|
ErrorCode::PaymentIntentPaymentAttemptFailed { data }
|
||||||
}
|
}
|
||||||
ApiErrorResponse::InvalidCardData { data } => ErrorCode::InvalidCardType, // Maybe it is better to de generalise this router error
|
ApiErrorResponse::InvalidCardData { data } => ErrorCode::InvalidCardType, // Maybe it is better to de generalize this router error
|
||||||
ApiErrorResponse::CardExpired { data } => ErrorCode::ExpiredCard,
|
ApiErrorResponse::CardExpired { data } => ErrorCode::ExpiredCard,
|
||||||
ApiErrorResponse::RefundFailed { data } => ErrorCode::RefundFailed, // Nothing at stripe to map
|
ApiErrorResponse::RefundFailed { data } => ErrorCode::RefundFailed, // Nothing at stripe to map
|
||||||
|
|
||||||
@ -347,12 +353,15 @@ impl From<ApiErrorResponse> for ErrorCode {
|
|||||||
ApiErrorResponse::InvalidRequestData { message } => {
|
ApiErrorResponse::InvalidRequestData { message } => {
|
||||||
ErrorCode::InvalidRequestData { message }
|
ErrorCode::InvalidRequestData { message }
|
||||||
}
|
}
|
||||||
|
ApiErrorResponse::PreconditionFailed { message } => {
|
||||||
|
ErrorCode::PreconditionFailed { message }
|
||||||
|
}
|
||||||
ApiErrorResponse::BadCredentials => ErrorCode::Unauthorized,
|
ApiErrorResponse::BadCredentials => ErrorCode::Unauthorized,
|
||||||
ApiErrorResponse::InvalidDataValue { field_name } => ErrorCode::ParameterMissing {
|
ApiErrorResponse::InvalidDataValue { field_name } => ErrorCode::ParameterMissing {
|
||||||
field_name: field_name.to_owned(),
|
field_name: field_name.to_owned(),
|
||||||
param: field_name.to_owned(),
|
param: field_name.to_owned(),
|
||||||
},
|
},
|
||||||
ApiErrorResponse::MaxiumumRefundCount => ErrorCode::MaximumRefundCount,
|
ApiErrorResponse::MaximumRefundCount => ErrorCode::MaximumRefundCount,
|
||||||
ApiErrorResponse::PaymentNotSucceeded => ErrorCode::PaymentFailed,
|
ApiErrorResponse::PaymentNotSucceeded => ErrorCode::PaymentFailed,
|
||||||
ApiErrorResponse::DuplicateMandate => ErrorCode::DuplicateMandate,
|
ApiErrorResponse::DuplicateMandate => ErrorCode::DuplicateMandate,
|
||||||
ApiErrorResponse::SuccessfulPaymentNotFound => ErrorCode::SuccessfulPaymentNotFound,
|
ApiErrorResponse::SuccessfulPaymentNotFound => ErrorCode::SuccessfulPaymentNotFound,
|
||||||
@ -403,6 +412,7 @@ impl actix_web::ResponseError for ErrorCode {
|
|||||||
| ErrorCode::PaymentIntentInvalidParameter { .. }
|
| ErrorCode::PaymentIntentInvalidParameter { .. }
|
||||||
| ErrorCode::SerdeQsError { .. }
|
| ErrorCode::SerdeQsError { .. }
|
||||||
| ErrorCode::InvalidRequestData { .. }
|
| ErrorCode::InvalidRequestData { .. }
|
||||||
|
| ErrorCode::PreconditionFailed { .. }
|
||||||
| ErrorCode::DuplicateMandate
|
| ErrorCode::DuplicateMandate
|
||||||
| ErrorCode::SuccessfulPaymentNotFound
|
| ErrorCode::SuccessfulPaymentNotFound
|
||||||
| ErrorCode::AddressNotFound
|
| ErrorCode::AddressNotFound
|
||||||
|
|||||||
@ -56,7 +56,7 @@ pub struct CheckoutThreeDS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&types::ConnectorAuthType> for CheckoutAuthType {
|
impl TryFrom<&types::ConnectorAuthType> for CheckoutAuthType {
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
|
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
|
||||||
if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type {
|
if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -64,12 +64,12 @@ impl TryFrom<&types::ConnectorAuthType> for CheckoutAuthType {
|
|||||||
processing_channel_id: key1.to_string(),
|
processing_channel_id: key1.to_string(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(errors::ValidateError.into())
|
Err(errors::ConnectorError::FailedToObtainAuthType.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest {
|
impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest {
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
||||||
let ccard = match item.request.payment_method_data {
|
let ccard = match item.request.payment_method_data {
|
||||||
api::PaymentMethod::Card(ref ccard) => Some(ccard),
|
api::PaymentMethod::Card(ref ccard) => Some(ccard),
|
||||||
@ -261,7 +261,7 @@ impl From<&PaymentVoidResponse> for enums::AttemptStatus {
|
|||||||
impl TryFrom<types::PaymentsCancelResponseRouterData<PaymentVoidResponse>>
|
impl TryFrom<types::PaymentsCancelResponseRouterData<PaymentVoidResponse>>
|
||||||
for types::PaymentsCancelRouterData
|
for types::PaymentsCancelRouterData
|
||||||
{
|
{
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::PaymentsCancelResponseRouterData<PaymentVoidResponse>,
|
item: types::PaymentsCancelResponseRouterData<PaymentVoidResponse>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
@ -294,7 +294,7 @@ pub struct RefundRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F> TryFrom<&types::RefundsRouterData<F>> for RefundRequest {
|
impl<F> TryFrom<&types::RefundsRouterData<F>> for RefundRequest {
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
||||||
let amount = item.request.refund_amount;
|
let amount = item.request.refund_amount;
|
||||||
let reference = item.request.refund_id.clone();
|
let reference = item.request.refund_id.clone();
|
||||||
@ -330,7 +330,7 @@ impl From<&CheckoutRefundResponse> for enums::RefundStatus {
|
|||||||
impl TryFrom<types::RefundsResponseRouterData<api::Execute, CheckoutRefundResponse>>
|
impl TryFrom<types::RefundsResponseRouterData<api::Execute, CheckoutRefundResponse>>
|
||||||
for types::RefundsRouterData<api::Execute>
|
for types::RefundsRouterData<api::Execute>
|
||||||
{
|
{
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::RefundsResponseRouterData<api::Execute, CheckoutRefundResponse>,
|
item: types::RefundsResponseRouterData<api::Execute, CheckoutRefundResponse>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
@ -348,7 +348,7 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, CheckoutRefundRespon
|
|||||||
impl TryFrom<types::RefundsResponseRouterData<api::RSync, CheckoutRefundResponse>>
|
impl TryFrom<types::RefundsResponseRouterData<api::RSync, CheckoutRefundResponse>>
|
||||||
for types::RefundsRouterData<api::RSync>
|
for types::RefundsRouterData<api::RSync>
|
||||||
{
|
{
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::RefundsResponseRouterData<api::RSync, CheckoutRefundResponse>,
|
item: types::RefundsResponseRouterData<api::RSync, CheckoutRefundResponse>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
@ -421,7 +421,7 @@ pub struct CheckoutRedirectResponse {
|
|||||||
impl TryFrom<types::RefundsResponseRouterData<api::Execute, &ActionResponse>>
|
impl TryFrom<types::RefundsResponseRouterData<api::Execute, &ActionResponse>>
|
||||||
for types::RefundsRouterData<api::Execute>
|
for types::RefundsRouterData<api::Execute>
|
||||||
{
|
{
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::RefundsResponseRouterData<api::Execute, &ActionResponse>,
|
item: types::RefundsResponseRouterData<api::Execute, &ActionResponse>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
@ -439,7 +439,7 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, &ActionResponse>>
|
|||||||
impl TryFrom<types::RefundsResponseRouterData<api::RSync, &ActionResponse>>
|
impl TryFrom<types::RefundsResponseRouterData<api::RSync, &ActionResponse>>
|
||||||
for types::RefundsRouterData<api::RSync>
|
for types::RefundsRouterData<api::RSync>
|
||||||
{
|
{
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ParsingError>;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
item: types::RefundsResponseRouterData<api::RSync, &ActionResponse>,
|
item: types::RefundsResponseRouterData<api::RSync, &ActionResponse>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
|
|||||||
@ -18,14 +18,14 @@ pub struct StripeAuthType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&types::ConnectorAuthType> for StripeAuthType {
|
impl TryFrom<&types::ConnectorAuthType> for StripeAuthType {
|
||||||
type Error = error_stack::Report<errors::ValidateError>;
|
type Error = error_stack::Report<errors::ConnectorError>;
|
||||||
fn try_from(item: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
|
fn try_from(item: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
|
||||||
if let types::ConnectorAuthType::HeaderKey { api_key } = item {
|
if let types::ConnectorAuthType::HeaderKey { api_key } = item {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
api_key: api_key.to_string(),
|
api_key: api_key.to_string(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(errors::ValidateError.into())
|
Err(errors::ConnectorError::FailedToObtainAuthType.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,7 +99,6 @@ impl_error_type!(AuthenticationError, "Authentication error");
|
|||||||
impl_error_type!(AuthorisationError, "Authorisation error");
|
impl_error_type!(AuthorisationError, "Authorisation error");
|
||||||
impl_error_type!(EncryptionError, "Encryption error");
|
impl_error_type!(EncryptionError, "Encryption error");
|
||||||
impl_error_type!(UnexpectedError, "Unexpected error");
|
impl_error_type!(UnexpectedError, "Unexpected error");
|
||||||
impl_error_type!(ValidateError, "validation failed");
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum BachError {
|
pub enum BachError {
|
||||||
@ -123,9 +122,6 @@ pub enum BachError {
|
|||||||
#[error("Environment configuration error: {0}")]
|
#[error("Environment configuration error: {0}")]
|
||||||
ConfigurationError(ConfigError),
|
ConfigurationError(ConfigError),
|
||||||
|
|
||||||
#[error("{{ error_description: Error while validating, error_message: {0} }}")]
|
|
||||||
EValidationError(error_stack::Report<ValidateError>), // Parsing error actually
|
|
||||||
|
|
||||||
#[error("{{ error_description: Database operation failed, error_message: {0} }}")]
|
#[error("{{ error_description: Database operation failed, error_message: {0} }}")]
|
||||||
EDatabaseError(error_stack::Report<DatabaseError>),
|
EDatabaseError(error_stack::Report<DatabaseError>),
|
||||||
|
|
||||||
@ -139,10 +135,6 @@ pub enum BachError {
|
|||||||
EIo(std::io::Error),
|
EIo(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
router_error_error_stack_specific!(
|
|
||||||
error_stack::Report<ValidateError>,
|
|
||||||
BachError::EValidationError(error_stack::Report<ValidateError>)
|
|
||||||
);
|
|
||||||
router_error_error_stack_specific!(
|
router_error_error_stack_specific!(
|
||||||
error_stack::Report<DatabaseError>,
|
error_stack::Report<DatabaseError>,
|
||||||
BachError::EDatabaseError(error_stack::Report<DatabaseError>)
|
BachError::EDatabaseError(error_stack::Report<DatabaseError>)
|
||||||
@ -202,8 +194,7 @@ impl ResponseError for BachError {
|
|||||||
match self {
|
match self {
|
||||||
BachError::EParsingError(_)
|
BachError::EParsingError(_)
|
||||||
| BachError::EAuthenticationError(_)
|
| BachError::EAuthenticationError(_)
|
||||||
| BachError::EAuthorisationError(_)
|
| BachError::EAuthorisationError(_) => StatusCode::BAD_REQUEST,
|
||||||
| BachError::EValidationError(_) => StatusCode::BAD_REQUEST,
|
|
||||||
|
|
||||||
BachError::EDatabaseError(_)
|
BachError::EDatabaseError(_)
|
||||||
| BachError::NotImplementedByConnector(_)
|
| BachError::NotImplementedByConnector(_)
|
||||||
@ -424,6 +415,8 @@ pub enum ValidationError {
|
|||||||
MissingRequiredField { field_name: String },
|
MissingRequiredField { field_name: String },
|
||||||
#[error("Incorrect value provided for field: {field_name}")]
|
#[error("Incorrect value provided for field: {field_name}")]
|
||||||
IncorrectValueProvided { field_name: &'static str },
|
IncorrectValueProvided { field_name: &'static str },
|
||||||
|
#[error("{message}")]
|
||||||
|
InvalidValue { message: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
|||||||
@ -42,17 +42,16 @@ pub enum ApiErrorResponse {
|
|||||||
field_name: String,
|
field_name: String,
|
||||||
expected_format: String,
|
expected_format: String,
|
||||||
},
|
},
|
||||||
#[error(
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "{message}")]
|
||||||
error_type = ErrorType::InvalidRequestError, code = "IR_07",
|
|
||||||
message = "{message}"
|
|
||||||
)]
|
|
||||||
InvalidRequestData { message: String },
|
InvalidRequestData { message: String },
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Refund amount exceeds the payment amount.")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Refund amount exceeds the payment amount.")]
|
||||||
RefundAmountExceedsPaymentAmount,
|
RefundAmountExceedsPaymentAmount,
|
||||||
|
/// Typically used when a field has invalid value, or deserialization of the value contained in
|
||||||
|
/// a field fails.
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Invalid value provided: {field_name}.")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Invalid value provided: {field_name}.")]
|
||||||
InvalidDataValue { field_name: &'static str },
|
InvalidDataValue { field_name: &'static str },
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Reached maximum refund attempts")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Reached maximum refund attempts")]
|
||||||
MaxiumumRefundCount,
|
MaximumRefundCount,
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_09", message = "This PaymentIntent could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}.")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_09", message = "This PaymentIntent could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}.")]
|
||||||
PaymentUnexpectedState {
|
PaymentUnexpectedState {
|
||||||
current_flow: String,
|
current_flow: String,
|
||||||
@ -60,12 +59,16 @@ pub enum ApiErrorResponse {
|
|||||||
current_value: String,
|
current_value: String,
|
||||||
states: String,
|
states: String,
|
||||||
},
|
},
|
||||||
|
/// Typically used when information involving multiple fields or previously provided
|
||||||
|
/// information doesn't satisfy a condition.
|
||||||
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_10", message = "{message}")]
|
||||||
|
PreconditionFailed { message: String },
|
||||||
|
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "The client_secret provided does not match the client_secret associated with the Payment.")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "The client_secret provided does not match the client_secret associated with the Payment.")]
|
||||||
ClientSecretInvalid,
|
ClientSecretInvalid,
|
||||||
|
|
||||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_01", message = "Payment failed while processing with connector. Retry payment.")]
|
#[error(error_type = ErrorType::ProcessingError, code = "CE_01", message = "Payment failed while processing with connector. Retry payment.")]
|
||||||
PaymentAuthorizationFailed { data: Option<serde_json::Value> }, //
|
PaymentAuthorizationFailed { data: Option<serde_json::Value> },
|
||||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_02", message = "Payment failed while processing with connector. Retry payment.")]
|
#[error(error_type = ErrorType::ProcessingError, code = "CE_02", message = "Payment failed while processing with connector. Retry payment.")]
|
||||||
PaymentAuthenticationFailed { data: Option<serde_json::Value> },
|
PaymentAuthenticationFailed { data: Option<serde_json::Value> },
|
||||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_03", message = "Capture attempt failed while processing with connector.")]
|
#[error(error_type = ErrorType::ProcessingError, code = "CE_03", message = "Capture attempt failed while processing with connector.")]
|
||||||
@ -142,7 +145,8 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
|||||||
ApiErrorResponse::InvalidDataFormat { .. }
|
ApiErrorResponse::InvalidDataFormat { .. }
|
||||||
| ApiErrorResponse::InvalidRequestData { .. } => StatusCode::UNPROCESSABLE_ENTITY, // 422
|
| ApiErrorResponse::InvalidRequestData { .. } => StatusCode::UNPROCESSABLE_ENTITY, // 422
|
||||||
ApiErrorResponse::RefundAmountExceedsPaymentAmount => StatusCode::BAD_REQUEST, // 400
|
ApiErrorResponse::RefundAmountExceedsPaymentAmount => StatusCode::BAD_REQUEST, // 400
|
||||||
ApiErrorResponse::MaxiumumRefundCount => StatusCode::BAD_REQUEST,
|
ApiErrorResponse::MaximumRefundCount => StatusCode::BAD_REQUEST, // 400
|
||||||
|
ApiErrorResponse::PreconditionFailed { .. } => StatusCode::BAD_REQUEST, // 400
|
||||||
|
|
||||||
ApiErrorResponse::PaymentAuthorizationFailed { .. }
|
ApiErrorResponse::PaymentAuthorizationFailed { .. }
|
||||||
| ApiErrorResponse::PaymentAuthenticationFailed { .. }
|
| ApiErrorResponse::PaymentAuthenticationFailed { .. }
|
||||||
@ -170,8 +174,8 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
|||||||
| ApiErrorResponse::DuplicatePaymentMethod
|
| ApiErrorResponse::DuplicatePaymentMethod
|
||||||
| ApiErrorResponse::DuplicateMandate => StatusCode::BAD_REQUEST, // 400
|
| ApiErrorResponse::DuplicateMandate => StatusCode::BAD_REQUEST, // 400
|
||||||
ApiErrorResponse::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, // 503
|
ApiErrorResponse::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, // 503
|
||||||
ApiErrorResponse::PaymentNotSucceeded => StatusCode::BAD_REQUEST,
|
ApiErrorResponse::PaymentNotSucceeded => StatusCode::BAD_REQUEST, // 400
|
||||||
ApiErrorResponse::NotImplemented => StatusCode::NOT_IMPLEMENTED,
|
ApiErrorResponse::NotImplemented => StatusCode::NOT_IMPLEMENTED, // 501
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ pub async fn get_address_for_payment_request(
|
|||||||
req_address: Option<&api::Address>,
|
req_address: Option<&api::Address>,
|
||||||
address_id: Option<&str>,
|
address_id: Option<&str>,
|
||||||
) -> CustomResult<Option<storage::Address>, errors::ApiErrorResponse> {
|
) -> CustomResult<Option<storage::Address>, errors::ApiErrorResponse> {
|
||||||
// TODO: Refactoring this function for more redability (TryFrom)
|
// TODO: Refactor this function for more readability (TryFrom)
|
||||||
Ok(match req_address {
|
Ok(match req_address {
|
||||||
Some(address) => {
|
Some(address) => {
|
||||||
match address_id {
|
match address_id {
|
||||||
@ -143,20 +143,14 @@ pub async fn get_token_for_recurring_mandate(
|
|||||||
|
|
||||||
let payment_method_id = {
|
let payment_method_id = {
|
||||||
if mandate.customer_id != customer {
|
if mandate.customer_id != customer {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Invalid Mandate ID")
|
message: "customer_id must match mandate customer_id".into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))?
|
||||||
field_name: "customer_id".to_string(),
|
|
||||||
expected_format: "customer_id must match mandate customer_id".to_string(),
|
|
||||||
}))?
|
|
||||||
}
|
}
|
||||||
if mandate.mandate_status != enums::MandateStatus::Active {
|
if mandate.mandate_status != enums::MandateStatus::Active {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Mandate is not active")
|
message: "mandate is not active".into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))?
|
||||||
field_name: "mandate_id".to_string(),
|
|
||||||
expected_format: "mandate_id of an active mandate".to_string(),
|
|
||||||
}))?
|
|
||||||
};
|
};
|
||||||
mandate.payment_method_id
|
mandate.payment_method_id
|
||||||
};
|
};
|
||||||
@ -174,12 +168,11 @@ pub async fn get_token_for_recurring_mandate(
|
|||||||
|
|
||||||
if let Some(payment_method_from_request) = req.payment_method {
|
if let Some(payment_method_from_request) = req.payment_method {
|
||||||
if payment_method_from_request != payment_method.payment_method {
|
if payment_method_from_request != payment_method.payment_method {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Invalid Mandate ID")
|
message: "payment method in request does not match previously provided payment \
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
method information"
|
||||||
field_name: "payment_method".to_string(),
|
.into()
|
||||||
expected_format: "valid payment method information".to_string(),
|
}))?
|
||||||
}))?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -192,7 +185,7 @@ pub async fn get_token_for_recurring_mandate(
|
|||||||
pub fn validate_merchant_id(
|
pub fn validate_merchant_id(
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
request_merchant_id: Option<&str>,
|
request_merchant_id: Option<&str>,
|
||||||
) -> CustomResult<(), errors::ValidateError> {
|
) -> CustomResult<(), errors::ApiErrorResponse> {
|
||||||
// Get Merchant Id from the merchant
|
// Get Merchant Id from the merchant
|
||||||
// or get from merchant account
|
// or get from merchant account
|
||||||
|
|
||||||
@ -200,9 +193,11 @@ pub fn validate_merchant_id(
|
|||||||
|
|
||||||
utils::when(
|
utils::when(
|
||||||
merchant_id.ne(request_merchant_id),
|
merchant_id.ne(request_merchant_id),
|
||||||
Err(report!(errors::ValidateError).attach_printable(format!(
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
"Invalid merchant_id: {request_merchant_id} not found in merchant account"
|
message: format!(
|
||||||
))),
|
"Invalid `merchant_id`: {request_merchant_id} not found in merchant account"
|
||||||
|
)
|
||||||
|
})),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +205,7 @@ pub fn validate_merchant_id(
|
|||||||
pub fn validate_request_amount_and_amount_to_capture(
|
pub fn validate_request_amount_and_amount_to_capture(
|
||||||
op_amount: Option<i32>,
|
op_amount: Option<i32>,
|
||||||
op_amount_to_capture: Option<i32>,
|
op_amount_to_capture: Option<i32>,
|
||||||
) -> CustomResult<(), errors::ValidateError> {
|
) -> CustomResult<(), errors::ApiErrorResponse> {
|
||||||
// If both amount and amount to capture is present
|
// If both amount and amount to capture is present
|
||||||
// then amount to be capture should be less than or equal to request amount
|
// then amount to be capture should be less than or equal to request amount
|
||||||
|
|
||||||
@ -222,10 +217,12 @@ pub fn validate_request_amount_and_amount_to_capture(
|
|||||||
|
|
||||||
utils::when(
|
utils::when(
|
||||||
!is_capture_amount_valid,
|
!is_capture_amount_valid,
|
||||||
Err(report!(errors::ValidateError).attach_printable(format!(
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
|
message: format!(
|
||||||
"amount_to_capture is greater than amount capture_amount: {:?} request_amount: {:?}",
|
"amount_to_capture is greater than amount capture_amount: {:?} request_amount: {:?}",
|
||||||
op_amount_to_capture, op_amount
|
op_amount_to_capture, op_amount
|
||||||
))),
|
)
|
||||||
|
})),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,12 +244,9 @@ fn validate_new_mandate_request(req: &api::PaymentsRequest) -> RouterResult<()>
|
|||||||
let confirm = req.confirm.get_required_value("confirm")?;
|
let confirm = req.confirm.get_required_value("confirm")?;
|
||||||
|
|
||||||
if !confirm {
|
if !confirm {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Confirm should be true for mandates")
|
message: "`confirm` must be `true` for mandates".into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))?
|
||||||
field_name: "confirm".to_string(),
|
|
||||||
expected_format: "confirm must be true for mandates".to_string(),
|
|
||||||
}))?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = req.customer_id.as_ref().get_required_value("customer_id")?;
|
let _ = req.customer_id.as_ref().get_required_value("customer_id")?;
|
||||||
@ -267,20 +261,19 @@ fn validate_new_mandate_request(req: &api::PaymentsRequest) -> RouterResult<()>
|
|||||||
.setup_future_usage
|
.setup_future_usage
|
||||||
.get_required_value("setup_future_usage")?
|
.get_required_value("setup_future_usage")?
|
||||||
{
|
{
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Key 'setup_future_usage' should be 'off_session' for mandates")
|
message: "`setup_future_usage` must be `off_session` for mandates".into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))?
|
||||||
field_name: "setup_future_usage".to_string(),
|
|
||||||
expected_format: "setup_future_usage must be off_session for mandates".to_string(),
|
|
||||||
}))?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mandate_data.customer_acceptance.acceptance_type == api::AcceptanceType::Online)
|
if (mandate_data.customer_acceptance.acceptance_type == api::AcceptanceType::Online)
|
||||||
&& mandate_data.customer_acceptance.online.is_none()
|
&& mandate_data.customer_acceptance.online.is_none()
|
||||||
{
|
{
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Key 'mandate_data.customer_acceptance.online' is required when 'mandate_data.customer_acceptance.acceptance_type' is 'online'")
|
message: "`mandate_data.customer_acceptance.online` is required when \
|
||||||
.change_context(errors::ApiErrorResponse::MissingRequiredField { field_name: "mandate_data.customer_acceptance.online".to_string() }))?
|
`mandate_data.customer_acceptance.acceptance_type` is `online`"
|
||||||
|
.into()
|
||||||
|
}))?
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -309,6 +302,7 @@ pub fn create_redirect_url(server: &Server, payment_attempt: &storage::PaymentAt
|
|||||||
payment_attempt.connector
|
payment_attempt.connector
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_recurring_mandate(req: &api::PaymentsRequest) -> RouterResult<()> {
|
fn validate_recurring_mandate(req: &api::PaymentsRequest) -> RouterResult<()> {
|
||||||
req.mandate_id.check_value_present("mandate_id")?;
|
req.mandate_id.check_value_present("mandate_id")?;
|
||||||
|
|
||||||
@ -316,22 +310,16 @@ fn validate_recurring_mandate(req: &api::PaymentsRequest) -> RouterResult<()> {
|
|||||||
|
|
||||||
let confirm = req.confirm.get_required_value("confirm")?;
|
let confirm = req.confirm.get_required_value("confirm")?;
|
||||||
if !confirm {
|
if !confirm {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("Confirm should be true for mandates")
|
message: "`confirm` must be `true` for mandates".into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))?
|
||||||
field_name: "confirm".to_string(),
|
|
||||||
expected_format: "confirm must be true for mandates".to_string(),
|
|
||||||
}))?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let off_session = req.off_session.get_required_value("off_session")?;
|
let off_session = req.off_session.get_required_value("off_session")?;
|
||||||
if !off_session {
|
if !off_session {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("off_session should be true for mandates")
|
message: "`off_session` should be `true` for mandates".into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))?
|
||||||
field_name: "off_session".to_string(),
|
|
||||||
expected_format: "off_session must be true for mandates".to_string(),
|
|
||||||
}))?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -119,9 +119,11 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
|
|
||||||
match payment_intent.status {
|
match payment_intent.status {
|
||||||
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
|
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("You cannot confirm this Payment because it has already succeeded after being previously confirmed.")
|
message: "You cannot confirm this Payment because it has already succeeded \
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat { field_name: "payment_id".to_string(), expected_format: "payment_id of pending payment".to_string() }))
|
after being previously confirmed."
|
||||||
|
.into()
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
_ => Ok((
|
_ => Ok((
|
||||||
Box::new(self),
|
Box::new(self),
|
||||||
@ -143,14 +145,14 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
payment_method_data: request.payment_method_data.clone(),
|
payment_method_data: request.payment_method_data.clone(),
|
||||||
force_sync: None,
|
force_sync: None,
|
||||||
refunds: vec![],
|
refunds: vec![],
|
||||||
},
|
},
|
||||||
Some(CustomerDetails {
|
Some(CustomerDetails {
|
||||||
customer_id: request.customer_id.clone(),
|
customer_id: request.customer_id.clone(),
|
||||||
name: request.name.clone(),
|
name: request.name.clone(),
|
||||||
email: request.email.clone(),
|
email: request.email.clone(),
|
||||||
phone: request.phone.clone(),
|
phone: request.phone.clone(),
|
||||||
phone_country_code: request.phone_country_code.clone(),
|
phone_country_code: request.phone_country_code.clone(),
|
||||||
})
|
}),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,9 +105,11 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
|
|
||||||
match payment_intent.status {
|
match payment_intent.status {
|
||||||
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
|
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable("You cannot confirm this Payment because it has already succeeded after being previously confirmed.")
|
message: "You cannot confirm this Payment because it has already succeeded \
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat { field_name: "payment_id".to_string(), expected_format: "payment_id of pending payment".to_string() }))
|
after being previously confirmed."
|
||||||
|
.into()
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
_ => Ok((
|
_ => Ok((
|
||||||
Box::new(self),
|
Box::new(self),
|
||||||
@ -125,12 +127,12 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
billing: billing_address.as_ref().map(|a| a.into()),
|
billing: billing_address.as_ref().map(|a| a.into()),
|
||||||
},
|
},
|
||||||
confirm: Some(payment_attempt.confirm),
|
confirm: Some(payment_attempt.confirm),
|
||||||
payment_attempt,
|
payment_attempt,
|
||||||
payment_method_data: None,
|
payment_method_data: None,
|
||||||
force_sync: None,
|
force_sync: None,
|
||||||
refunds: vec![]
|
refunds: vec![],
|
||||||
},
|
},
|
||||||
Some(customer_details)
|
Some(customer_details),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,14 +124,11 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
|
|
||||||
match payment_intent.status {
|
match payment_intent.status {
|
||||||
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
|
enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
|
||||||
Err(report!(errors::ValidateError)
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
.attach_printable(
|
message:
|
||||||
"You cannot update this Payment because it has already succeeded/failed.",
|
"You cannot update this Payment because it has already succeeded/failed."
|
||||||
)
|
.into()
|
||||||
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
|
}))
|
||||||
field_name: "payment_id".to_string(),
|
|
||||||
expected_format: "payment_id of pending payment".to_string(),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
_ => Ok((
|
_ => Ok((
|
||||||
Box::new(self),
|
Box::new(self),
|
||||||
|
|||||||
@ -359,7 +359,7 @@ pub async fn validate_and_create_refund(
|
|||||||
.change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?;
|
.change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?;
|
||||||
|
|
||||||
validator::validate_maximum_refund_against_payment_attempt(&all_refunds)
|
validator::validate_maximum_refund_against_payment_attempt(&all_refunds)
|
||||||
.change_context(errors::ApiErrorResponse::MaxiumumRefundCount)?;
|
.change_context(errors::ApiErrorResponse::MaximumRefundCount)?;
|
||||||
|
|
||||||
refund_create_req = mk_new_refund(
|
refund_create_req = mk_new_refund(
|
||||||
req,
|
req,
|
||||||
|
|||||||
@ -534,11 +534,10 @@ pub async fn authenticate_merchant<'a>(
|
|||||||
let admin_api_key =
|
let admin_api_key =
|
||||||
get_api_key(request).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
get_api_key(request).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||||
if admin_api_key != "test_admin" {
|
if admin_api_key != "test_admin" {
|
||||||
Err(report!(errors::ValidateError)
|
// TODO: The BadCredentials error is too specific for api keys, and inappropriate
|
||||||
.attach_printable("Admin Authentication Failure")
|
// for AdminApiKey/MerchantID
|
||||||
// TODO: The BadCredentials error is too specific for api keys, and inappropriate for AdminApiKey/MerchantID
|
Err(report!(errors::ApiErrorResponse::BadCredentials)
|
||||||
// https://juspay.atlassian.net/browse/ORCA-366
|
.attach_printable("Admin Authentication Failure"))?;
|
||||||
.change_context(errors::ApiErrorResponse::BadCredentials))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(storage::MerchantAccount {
|
Ok(storage::MerchantAccount {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use once_cell::sync::Lazy;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::errors::{self, ApiErrorResponse, CustomResult, RouterResult, ValidateError},
|
core::errors::{self, ApiErrorResponse, CustomResult, RouterResult},
|
||||||
logger,
|
logger,
|
||||||
types::api::AddressDetails,
|
types::api::AddressDetails,
|
||||||
utils::when,
|
utils::when,
|
||||||
@ -111,20 +111,20 @@ pub(crate) fn merge_json_values(a: &mut serde_json::Value, b: &serde_json::Value
|
|||||||
|
|
||||||
// TODO: change Name
|
// TODO: change Name
|
||||||
pub trait ValidateVar {
|
pub trait ValidateVar {
|
||||||
fn validate(self) -> CustomResult<Self, ValidateError>
|
fn validate(self) -> CustomResult<Self, errors::ValidationError>
|
||||||
where
|
where
|
||||||
Self: std::marker::Sized;
|
Self: std::marker::Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ValidateCall<T, F> {
|
pub trait ValidateCall<T, F> {
|
||||||
fn validate_opt(self, func: F) -> CustomResult<(), ValidateError>;
|
fn validate_opt(self, func: F) -> CustomResult<(), errors::ValidationError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, F> ValidateCall<T, F> for Option<&T>
|
impl<T, F> ValidateCall<T, F> for Option<&T>
|
||||||
where
|
where
|
||||||
F: Fn(&T) -> CustomResult<(), ValidateError>,
|
F: Fn(&T) -> CustomResult<(), errors::ValidationError>,
|
||||||
{
|
{
|
||||||
fn validate_opt(self, func: F) -> CustomResult<(), ValidateError> {
|
fn validate_opt(self, func: F) -> CustomResult<(), errors::ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Some(val) => func(val),
|
Some(val) => func(val),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
@ -132,7 +132,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_email(email: &str) -> CustomResult<(), ValidateError> {
|
pub fn validate_email(email: &str) -> CustomResult<(), errors::ValidationError> {
|
||||||
#[deny(clippy::invalid_regex)]
|
#[deny(clippy::invalid_regex)]
|
||||||
static EMAIL_REGEX: Lazy<Option<Regex>> = Lazy::new(|| {
|
static EMAIL_REGEX: Lazy<Option<Regex>> = Lazy::new(|| {
|
||||||
match Regex::new(
|
match Regex::new(
|
||||||
@ -147,26 +147,32 @@ pub fn validate_email(email: &str) -> CustomResult<(), ValidateError> {
|
|||||||
});
|
});
|
||||||
let email_regex = match EMAIL_REGEX.as_ref() {
|
let email_regex = match EMAIL_REGEX.as_ref() {
|
||||||
Some(regex) => Ok(regex),
|
Some(regex) => Ok(regex),
|
||||||
None => Err(report!(ValidateError).attach_printable("Invalid regex expression")),
|
None => Err(report!(errors::ValidationError::InvalidValue {
|
||||||
|
message: "Invalid regex expression".into()
|
||||||
|
})),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
const EMAIL_MAX_LENGTH: usize = 319;
|
const EMAIL_MAX_LENGTH: usize = 319;
|
||||||
if email.is_empty() || email.chars().count() > EMAIL_MAX_LENGTH {
|
if email.is_empty() || email.chars().count() > EMAIL_MAX_LENGTH {
|
||||||
return Err(report!(ValidateError).attach_printable("Invalid email address length"));
|
return Err(report!(errors::ValidationError::InvalidValue {
|
||||||
|
message: "Email address is either empty or exceeds maximum allowed length".into()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !email_regex.is_match(email) {
|
if !email_regex.is_match(email) {
|
||||||
return Err(report!(ValidateError).attach_printable("Invalid email format"));
|
return Err(report!(errors::ValidationError::InvalidValue {
|
||||||
|
message: "Invalid email address format".into()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_address(address: &serde_json::Value) -> CustomResult<(), ValidateError> {
|
pub fn validate_address(address: &serde_json::Value) -> CustomResult<(), errors::ValidationError> {
|
||||||
if let Err(err) = serde_json::from_value::<AddressDetails>(address.clone()) {
|
if let Err(err) = serde_json::from_value::<AddressDetails>(address.clone()) {
|
||||||
return Err(
|
return Err(report!(errors::ValidationError::InvalidValue {
|
||||||
report!(ValidateError).attach_printable(format!("Address is invalid {:?}", err))
|
message: format!("Invalid address: {err}")
|
||||||
);
|
}));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user