mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 21:37:41 +08:00
chore: move RouterData Request types to hyperswitch_domain_models crate (#4723)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -1,4 +1,3 @@
|
||||
pub mod api_error_response;
|
||||
pub mod customers_error_response;
|
||||
pub mod error_handlers;
|
||||
pub mod transformers;
|
||||
@ -11,7 +10,10 @@ use std::fmt::Display;
|
||||
use actix_web::{body::BoxBody, ResponseError};
|
||||
pub use common_utils::errors::{CustomResult, ParsingError, ValidationError};
|
||||
use diesel_models::errors as storage_errors;
|
||||
pub use hyperswitch_domain_models::errors::StorageError as DataStorageError;
|
||||
pub use hyperswitch_domain_models::errors::{
|
||||
api_error_response::{ApiErrorResponse, ErrorType, NotImplementedMessage},
|
||||
StorageError as DataStorageError,
|
||||
};
|
||||
pub use redis_interface::errors::RedisError;
|
||||
use scheduler::errors as sch_errors;
|
||||
use storage_impl::errors as storage_impl_errors;
|
||||
@ -19,7 +21,6 @@ use storage_impl::errors as storage_impl_errors;
|
||||
pub use user::*;
|
||||
|
||||
pub use self::{
|
||||
api_error_response::{ApiErrorResponse, NotImplementedMessage},
|
||||
customers_error_response::CustomersErrorResponse,
|
||||
sch_errors::*,
|
||||
storage_errors::*,
|
||||
|
||||
@ -1,328 +0,0 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use http::StatusCode;
|
||||
use scheduler::errors::{PTError, ProcessTrackerError};
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ErrorType {
|
||||
InvalidRequestError,
|
||||
ObjectNotFound,
|
||||
RouterError,
|
||||
ProcessingError,
|
||||
BadGateway,
|
||||
ServerNotAvailable,
|
||||
DuplicateRequest,
|
||||
ValidationError,
|
||||
ConnectorError,
|
||||
LockTimeout,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, router_derive::ApiError)]
|
||||
#[error(error_type_enum = ErrorType)]
|
||||
pub enum ApiErrorResponse {
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "IR_00", message = "{message:?}")]
|
||||
NotImplemented { message: NotImplementedMessage },
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_01",
|
||||
message = "API key not provided or invalid API key used"
|
||||
)]
|
||||
Unauthorized,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_02", message = "Unrecognized request URL")]
|
||||
InvalidRequestUrl,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_03", message = "The HTTP method is not applicable for this API")]
|
||||
InvalidHttpMethod,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_04", message = "Missing required param: {field_name}")]
|
||||
MissingRequiredField { field_name: &'static str },
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_05",
|
||||
message = "{field_name} contains invalid data. Expected format is {expected_format}"
|
||||
)]
|
||||
InvalidDataFormat {
|
||||
field_name: String,
|
||||
expected_format: String,
|
||||
},
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_06", message = "{message}")]
|
||||
InvalidRequestData { message: String },
|
||||
/// 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}")]
|
||||
InvalidDataValue { field_name: &'static str },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Client secret was not provided")]
|
||||
ClientSecretNotGiven,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Client secret has expired")]
|
||||
ClientSecretExpired,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_09", message = "The client_secret provided does not match the client_secret associated with the Payment")]
|
||||
ClientSecretInvalid,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_10", message = "Customer has active mandate/subsciption")]
|
||||
MandateActive,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_11", message = "Customer has already been redacted")]
|
||||
CustomerRedacted,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_12", message = "Reached maximum refund attempts")]
|
||||
MaximumRefundCount,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_13", message = "The refund amount exceeds the amount captured")]
|
||||
RefundAmountExceedsPaymentAmount,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_14", message = "This Payment could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}")]
|
||||
PaymentUnexpectedState {
|
||||
current_flow: String,
|
||||
field_name: String,
|
||||
current_value: String,
|
||||
states: String,
|
||||
},
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_15", message = "Invalid Ephemeral Key for the customer")]
|
||||
InvalidEphemeralKey,
|
||||
/// Typically used when information involving multiple fields or previously provided information doesn't satisfy a condition.
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_16", message = "{message}")]
|
||||
PreconditionFailed { message: String },
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_17",
|
||||
message = "Access forbidden, invalid JWT token was used"
|
||||
)]
|
||||
InvalidJwtToken,
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_18",
|
||||
message = "{message}",
|
||||
)]
|
||||
GenericUnauthorized { message: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_19", message = "{message}")]
|
||||
NotSupported { message: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_20", message = "{flow} flow not supported by the {connector} connector")]
|
||||
FlowNotSupported { flow: String, connector: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_21", message = "Missing required params")]
|
||||
MissingRequiredFields { field_names: Vec<&'static str> },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_22", message = "Access forbidden. Not authorized to access this resource {resource}")]
|
||||
AccessForbidden { resource: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_23", message = "{message}")]
|
||||
FileProviderNotSupported { message: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_23", message = "{message}")]
|
||||
UnprocessableEntity { message: String },
|
||||
#[error(
|
||||
error_type = ErrorType::ProcessingError, code = "IR_24",
|
||||
message = "Invalid {wallet_name} wallet token"
|
||||
)]
|
||||
InvalidWalletToken { wallet_name: String },
|
||||
#[error(error_type = ErrorType::ConnectorError, code = "CE_00", message = "{code}: {message}", ignore = "status_code")]
|
||||
ExternalConnectorError {
|
||||
code: String,
|
||||
message: String,
|
||||
connector: String,
|
||||
status_code: u16,
|
||||
reason: Option<String>,
|
||||
},
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_01", message = "Payment failed during authorization with connector. Retry payment")]
|
||||
PaymentAuthorizationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_02", message = "Payment failed during authentication with connector. Retry payment")]
|
||||
PaymentAuthenticationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_03", message = "Capture attempt failed while processing with connector")]
|
||||
PaymentCaptureFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_04", message = "The card data is invalid")]
|
||||
InvalidCardData { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "CE_04", message = "Payout validation failed")]
|
||||
PayoutFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_05", message = "The card has expired")]
|
||||
CardExpired { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_06", message = "Refund failed while processing with connector. Retry refund")]
|
||||
RefundFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_07", message = "Verification failed while processing with connector. Retry operation")]
|
||||
VerificationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_08", message = "Dispute operation failed while processing with connector. Retry operation")]
|
||||
DisputeFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "HE_00", message = "Something went wrong")]
|
||||
InternalServerError,
|
||||
#[error(error_type = ErrorType::LockTimeout, code = "HE_00", message = "Resource is busy. Please try again later.")]
|
||||
ResourceBusy,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "Duplicate refund request. Refund already attempted with the refund ID")]
|
||||
DuplicateRefundRequest,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "Duplicate mandate request. Mandate already attempted with the Mandate ID")]
|
||||
DuplicateMandate,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The merchant account with the specified details already exists in our records")]
|
||||
DuplicateMerchantAccount,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The merchant connector account with the specified profile_id '{profile_id}' and connector_label '{connector_label}' already exists in our records")]
|
||||
DuplicateMerchantConnectorAccount {
|
||||
profile_id: String,
|
||||
connector_label: String,
|
||||
},
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The payment method with the specified details already exists in our records")]
|
||||
DuplicatePaymentMethod,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The payment with the specified payment_id already exists in our records")]
|
||||
DuplicatePayment { payment_id: String },
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The payout with the specified payout_id '{payout_id}' already exists in our records")]
|
||||
DuplicatePayout { payout_id: String },
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The config with the specified key already exists in our records")]
|
||||
DuplicateConfig,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Refund does not exist in our records")]
|
||||
RefundNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Customer does not exist in our records")]
|
||||
CustomerNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Config key does not exist in our records.")]
|
||||
ConfigNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Payment does not exist in our records")]
|
||||
PaymentNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Payment method does not exist in our records")]
|
||||
PaymentMethodNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Merchant account does not exist in our records")]
|
||||
MerchantAccountNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Merchant connector account does not exist in our records")]
|
||||
MerchantConnectorAccountNotFound { id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Business profile with the given id '{id}' does not exist in our records")]
|
||||
BusinessProfileNotFound { id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Poll with the given id '{id}' does not exist in our records")]
|
||||
PollNotFound { id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Resource ID does not exist in our records")]
|
||||
ResourceIdNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Mandate does not exist in our records")]
|
||||
MandateNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Authentication does not exist in our records")]
|
||||
AuthenticationNotFound { id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Failed to update mandate")]
|
||||
MandateUpdateFailed,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "API Key does not exist in our records")]
|
||||
ApiKeyNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Payout does not exist in our records")]
|
||||
PayoutNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Event does not exist in our records")]
|
||||
EventNotFound,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "Invalid mandate id passed from connector")]
|
||||
MandateSerializationFailed,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "Unable to parse the mandate identifier passed from connector")]
|
||||
MandateDeserializationFailed,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "Return URL is not configured and not passed in payments request")]
|
||||
ReturnUrlUnavailable,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "This refund is not possible through Hyperswitch. Please raise the refund through {connector} dashboard")]
|
||||
RefundNotPossible { connector: String },
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "Mandate Validation Failed" )]
|
||||
MandateValidationFailed { reason: String },
|
||||
#[error(error_type= ErrorType::ValidationError, code = "HE_03", message = "The payment has not succeeded yet. Please pass a successful payment to initiate refund")]
|
||||
PaymentNotSucceeded,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "The specified merchant connector account is disabled")]
|
||||
MerchantConnectorAccountDisabled,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "{code}: {message}")]
|
||||
PaymentBlockedError {
|
||||
code: u16,
|
||||
message: String,
|
||||
status: String,
|
||||
reason: String,
|
||||
},
|
||||
#[error(error_type= ErrorType::ObjectNotFound, code = "HE_04", message = "Successful payment not found for the given payment id")]
|
||||
SuccessfulPaymentNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "The connector provided in the request is incorrect or not available")]
|
||||
IncorrectConnectorNameGiven,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "Address does not exist in our records")]
|
||||
AddressNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "Dispute does not exist in our records")]
|
||||
DisputeNotFound { dispute_id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "File does not exist in our records")]
|
||||
FileNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "File not available")]
|
||||
FileNotAvailable,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "Dispute status validation failed")]
|
||||
DisputeStatusValidationFailed { reason: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "Card with the provided iin does not exist")]
|
||||
InvalidCardIin,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "The provided card IIN length is invalid, please provide an iin with 6 or 8 digits")]
|
||||
InvalidCardIinLength,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "File validation failed")]
|
||||
FileValidationFailed { reason: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "File not found / valid in the request")]
|
||||
MissingFile,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "Dispute id not found in the request")]
|
||||
MissingDisputeId,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "File purpose not found in the request or is invalid")]
|
||||
MissingFilePurpose,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "File content type not found / valid")]
|
||||
MissingFileContentType,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_05", message = "{message}")]
|
||||
GenericNotFoundError { message: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_01", message = "{message}")]
|
||||
GenericDuplicateError { message: String },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_01", message = "Failed to authenticate the webhook")]
|
||||
WebhookAuthenticationFailed,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "WE_04", message = "Webhook resource not found")]
|
||||
WebhookResourceNotFound,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_02", message = "Bad request received in webhook")]
|
||||
WebhookBadRequest,
|
||||
#[error(error_type = ErrorType::RouterError, code = "WE_03", message = "There was some issue processing the webhook")]
|
||||
WebhookProcessingFailure,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "HE_04", message = "required payment method is not configured or configured incorrectly for all configured connectors")]
|
||||
IncorrectPaymentMethodConfiguration,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_05", message = "Unable to process the webhook body")]
|
||||
WebhookUnprocessableEntity,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Payment Link does not exist in our records")]
|
||||
PaymentLinkNotFound,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_05", message = "Merchant Secret set my merchant for webhook source verification is invalid")]
|
||||
WebhookInvalidMerchantSecret,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_19", message = "{message}")]
|
||||
CurrencyNotSupported { message: String },
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code= "HE_00", message = "{component} health check is failing with error: {message}")]
|
||||
HealthCheckError {
|
||||
component: &'static str,
|
||||
message: String,
|
||||
},
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_24", message = "Merchant connector account is configured with invalid {config}")]
|
||||
InvalidConnectorConfiguration { config: String },
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_01", message = "Failed to convert currency to minor unit")]
|
||||
CurrencyConversionFailed,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
|
||||
PaymentMethodDeleteFailed,
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_26",
|
||||
message = "Invalid Cookie"
|
||||
)]
|
||||
InvalidCookie,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_27", message = "Extended card info does not exist")]
|
||||
ExtendedCardInfoNotFound,
|
||||
}
|
||||
|
||||
impl PTError for ApiErrorResponse {
|
||||
fn to_pt_error(&self) -> ProcessTrackerError {
|
||||
ProcessTrackerError::EApiErrorResponse
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum NotImplementedMessage {
|
||||
Reason(String),
|
||||
Default,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for NotImplementedMessage {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Reason(message) => write!(fmt, "{message} is not implemented"),
|
||||
Self::Default => {
|
||||
write!(
|
||||
fmt,
|
||||
"This API is under development and will be made available soon."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::core::fmt::Display for ApiErrorResponse {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
r#"{{"error":{}}}"#,
|
||||
serde_json::to_string(self).unwrap_or_else(|_| "API error response".to_string())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl actix_web::ResponseError for ApiErrorResponse {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
common_utils::errors::ErrorSwitch::<api_models::errors::types::ApiErrorResponse>::switch(
|
||||
self,
|
||||
)
|
||||
.status_code()
|
||||
}
|
||||
|
||||
fn error_response(&self) -> actix_web::HttpResponse {
|
||||
common_utils::errors::ErrorSwitch::<api_models::errors::types::ApiErrorResponse>::switch(
|
||||
self,
|
||||
)
|
||||
.error_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::services::EmbedError for error_stack::Report<ApiErrorResponse> {}
|
||||
@ -1,312 +1,7 @@
|
||||
use api_models::errors::types::Extra;
|
||||
use common_utils::errors::ErrorSwitch;
|
||||
use http::StatusCode;
|
||||
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;
|
||||
|
||||
use super::{ApiErrorResponse, ConnectorError, CustomersErrorResponse, StorageError};
|
||||
|
||||
impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorResponse {
|
||||
fn switch(&self) -> api_models::errors::types::ApiErrorResponse {
|
||||
use api_models::errors::types::{ApiError, ApiErrorResponse as AER};
|
||||
|
||||
match self {
|
||||
Self::NotImplemented { message } => {
|
||||
AER::NotImplemented(ApiError::new("IR", 0, format!("{message:?}"), None))
|
||||
}
|
||||
Self::Unauthorized => AER::Unauthorized(ApiError::new(
|
||||
"IR",
|
||||
1,
|
||||
"API key not provided or invalid API key used", None
|
||||
)),
|
||||
Self::InvalidRequestUrl => {
|
||||
AER::NotFound(ApiError::new("IR", 2, "Unrecognized request URL", None))
|
||||
}
|
||||
Self::InvalidHttpMethod => AER::MethodNotAllowed(ApiError::new(
|
||||
"IR",
|
||||
3,
|
||||
"The HTTP method is not applicable for this API", None
|
||||
)),
|
||||
Self::MissingRequiredField { field_name } => AER::BadRequest(
|
||||
ApiError::new("IR", 4, format!("Missing required param: {field_name}"), None),
|
||||
),
|
||||
Self::InvalidDataFormat {
|
||||
field_name,
|
||||
expected_format,
|
||||
} => AER::Unprocessable(ApiError::new(
|
||||
"IR",
|
||||
5,
|
||||
format!(
|
||||
"{field_name} contains invalid data. Expected format is {expected_format}"
|
||||
), None
|
||||
)),
|
||||
Self::InvalidRequestData { message } => {
|
||||
AER::Unprocessable(ApiError::new("IR", 6, message.to_string(), None))
|
||||
}
|
||||
Self::InvalidDataValue { field_name } => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
7,
|
||||
format!("Invalid value provided: {field_name}"), None
|
||||
)),
|
||||
Self::ClientSecretNotGiven => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
8,
|
||||
"client_secret was not provided", None
|
||||
)),
|
||||
Self::ClientSecretInvalid => {
|
||||
AER::BadRequest(ApiError::new("IR", 9, "The client_secret provided does not match the client_secret associated with the Payment", None))
|
||||
}
|
||||
Self::CurrencyNotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 9, message, None))
|
||||
}
|
||||
Self::MandateActive => {
|
||||
AER::BadRequest(ApiError::new("IR", 10, "Customer has active mandate/subsciption", None))
|
||||
}
|
||||
Self::CustomerRedacted => {
|
||||
AER::BadRequest(ApiError::new("IR", 11, "Customer has already been redacted", None))
|
||||
}
|
||||
Self::MaximumRefundCount => AER::BadRequest(ApiError::new("IR", 12, "Reached maximum refund attempts", None)),
|
||||
Self::RefundAmountExceedsPaymentAmount => {
|
||||
AER::BadRequest(ApiError::new("IR", 13, "The refund amount exceeds the amount captured", None))
|
||||
}
|
||||
Self::PaymentUnexpectedState {
|
||||
current_flow,
|
||||
field_name,
|
||||
current_value,
|
||||
states,
|
||||
} => AER::BadRequest(ApiError::new("IR", 14, format!("This Payment could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}"), None)),
|
||||
Self::InvalidEphemeralKey => AER::Unauthorized(ApiError::new("IR", 15, "Invalid Ephemeral Key for the customer", None)),
|
||||
Self::PreconditionFailed { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 16, message.to_string(), None))
|
||||
}
|
||||
Self::InvalidJwtToken => AER::Unauthorized(ApiError::new("IR", 17, "Access forbidden, invalid JWT token was used", None)),
|
||||
Self::GenericUnauthorized { message } => {
|
||||
AER::Unauthorized(ApiError::new("IR", 18, message.to_string(), None))
|
||||
},
|
||||
Self::ClientSecretExpired => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
19,
|
||||
"The provided client_secret has expired", None
|
||||
)),
|
||||
Self::MissingRequiredFields { field_names } => AER::BadRequest(
|
||||
ApiError::new("IR", 21, "Missing required params".to_string(), Some(Extra {data: Some(serde_json::json!(field_names)), ..Default::default() })),
|
||||
),
|
||||
Self::AccessForbidden {resource} => {
|
||||
AER::ForbiddenCommonResource(ApiError::new("IR", 22, format!("Access forbidden. Not authorized to access this resource {resource}"), None))
|
||||
},
|
||||
Self::FileProviderNotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 23, message.to_string(), None))
|
||||
},
|
||||
Self::UnprocessableEntity {message} => AER::Unprocessable(ApiError::new("IR", 23, message.to_string(), None)),
|
||||
Self::InvalidWalletToken { wallet_name} => AER::Unprocessable(ApiError::new(
|
||||
"IR",
|
||||
24,
|
||||
format!("Invalid {wallet_name} wallet token"), None
|
||||
)),
|
||||
Self::ExternalConnectorError {
|
||||
code,
|
||||
message,
|
||||
connector,
|
||||
reason,
|
||||
status_code,
|
||||
} => AER::ConnectorError(ApiError::new("CE", 0, format!("{code}: {message}"), Some(Extra {connector: Some(connector.clone()), reason: reason.to_owned().map(Into::into), ..Default::default()})), StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)),
|
||||
Self::PaymentAuthorizationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Payment failed during authorization with connector. Retry payment", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::PaymentAuthenticationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 2, "Payment failed during authentication with connector. Retry payment", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::PaymentCaptureFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 3, "Capture attempt failed while processing with connector", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::DisputeFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Dispute operation failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::InvalidCardData { data } => AER::BadRequest(ApiError::new("CE", 4, "The card data is invalid", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::CardExpired { data } => AER::BadRequest(ApiError::new("CE", 5, "The card has expired", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::RefundFailed { data } => AER::BadRequest(ApiError::new("CE", 6, "Refund failed while processing with connector. Retry refund", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::VerificationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 7, "Verification failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
},
|
||||
Self::MandateUpdateFailed | Self::MandateSerializationFailed | Self::MandateDeserializationFailed | Self::InternalServerError => {
|
||||
AER::InternalServerError(ApiError::new("HE", 0, "Something went wrong", None))
|
||||
},
|
||||
Self::HealthCheckError { message,component } => {
|
||||
AER::InternalServerError(ApiError::new("HE",0,format!("{} health check failed with error: {}",component,message),None))
|
||||
},
|
||||
Self::PayoutFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 4, "Payout failed while processing with connector.", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
},
|
||||
Self::DuplicateRefundRequest => AER::BadRequest(ApiError::new("HE", 1, "Duplicate refund request. Refund already attempted with the refund ID", None)),
|
||||
Self::DuplicateMandate => AER::BadRequest(ApiError::new("HE", 1, "Duplicate mandate request. Mandate already attempted with the Mandate ID", None)),
|
||||
Self::DuplicateMerchantAccount => AER::BadRequest(ApiError::new("HE", 1, "The merchant account with the specified details already exists in our records", None)),
|
||||
Self::DuplicateMerchantConnectorAccount { profile_id, connector_label: connector_name } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, format!("The merchant connector account with the specified profile_id '{profile_id}' and connector_label '{connector_name}' already exists in our records"), None))
|
||||
}
|
||||
Self::DuplicatePaymentMethod => AER::BadRequest(ApiError::new("HE", 1, "The payment method with the specified details already exists in our records", None)),
|
||||
Self::DuplicatePayment { payment_id } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, "The payment with the specified payment_id already exists in our records", Some(Extra {reason: Some(format!("{payment_id} already exists")), ..Default::default()})))
|
||||
}
|
||||
Self::DuplicatePayout { payout_id } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, format!("The payout with the specified payout_id '{payout_id}' already exists in our records"), None))
|
||||
}
|
||||
Self::GenericDuplicateError { message } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, message, None))
|
||||
}
|
||||
Self::RefundNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Refund does not exist in our records.", None))
|
||||
}
|
||||
Self::CustomerNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Customer does not exist in our records", None))
|
||||
}
|
||||
Self::ConfigNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Config key does not exist in our records.", None))
|
||||
},
|
||||
Self::DuplicateConfig => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, "The config with the specified key already exists in our records", None))
|
||||
}
|
||||
Self::PaymentNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment does not exist in our records", None))
|
||||
}
|
||||
Self::PaymentMethodNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment method does not exist in our records", None))
|
||||
}
|
||||
Self::MerchantAccountNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Merchant account does not exist in our records", None))
|
||||
}
|
||||
Self::MerchantConnectorAccountNotFound {id } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Merchant connector account does not exist in our records", Some(Extra {reason: Some(format!("{id} does not exist")), ..Default::default()})))
|
||||
}
|
||||
Self::MerchantConnectorAccountDisabled => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "The selected merchant connector account is disabled", None))
|
||||
}
|
||||
Self::ResourceIdNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Resource ID does not exist in our records", None))
|
||||
}
|
||||
Self::MandateNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Mandate does not exist in our records", None))
|
||||
}
|
||||
Self::PayoutNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payout does not exist in our records", None))
|
||||
}
|
||||
Self::EventNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Event does not exist in our records", None))
|
||||
}
|
||||
Self::ReturnUrlUnavailable => AER::NotFound(ApiError::new("HE", 3, "Return URL is not configured and not passed in payments request", None)),
|
||||
Self::RefundNotPossible { connector } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, format!("This refund is not possible through Hyperswitch. Please raise the refund through {connector} dashboard"), None))
|
||||
}
|
||||
Self::MandateValidationFailed { reason } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "Mandate Validation Failed", Some(Extra { reason: Some(reason.to_owned()), ..Default::default() })))
|
||||
}
|
||||
Self::PaymentNotSucceeded => AER::BadRequest(ApiError::new("HE", 3, "The payment has not succeeded yet. Please pass a successful payment to initiate refund", None)),
|
||||
Self::PaymentBlockedError {
|
||||
message,
|
||||
reason,
|
||||
..
|
||||
} => AER::DomainError(ApiError::new("HE", 3, message, Some(Extra { reason: Some(reason.clone()), ..Default::default() }))),
|
||||
Self::SuccessfulPaymentNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "Successful payment not found for the given payment id", None))
|
||||
}
|
||||
Self::IncorrectConnectorNameGiven => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "The connector provided in the request is incorrect or not available", None))
|
||||
}
|
||||
Self::AddressNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "Address does not exist in our records", None))
|
||||
},
|
||||
Self::GenericNotFoundError { message } => {
|
||||
AER::NotFound(ApiError::new("HE", 5, message, None))
|
||||
},
|
||||
Self::ApiKeyNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "API Key does not exist in our records", None))
|
||||
}
|
||||
Self::NotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "Payment method type not supported", Some(Extra {reason: Some(message.to_owned()), ..Default::default()})))
|
||||
},
|
||||
Self::InvalidCardIin => AER::BadRequest(ApiError::new("HE", 3, "The provided card IIN does not exist", None)),
|
||||
Self::InvalidCardIinLength => AER::BadRequest(ApiError::new("HE", 3, "The provided card IIN length is invalid, please provide an IIN with 6 digits", None)),
|
||||
Self::FlowNotSupported { flow, connector } => {
|
||||
AER::BadRequest(ApiError::new("IR", 20, format!("{flow} flow not supported"), Some(Extra {connector: Some(connector.to_owned()), ..Default::default()}))) //FIXME: error message
|
||||
}
|
||||
Self::DisputeNotFound { .. } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Dispute does not exist in our records", None))
|
||||
},
|
||||
Self::AuthenticationNotFound { .. } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Authentication does not exist in our records", None))
|
||||
},
|
||||
Self::BusinessProfileNotFound { id } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, format!("Business profile with the given id {id} does not exist"), None))
|
||||
}
|
||||
Self::FileNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File does not exist in our records", None))
|
||||
}
|
||||
Self::PollNotFound { .. } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Poll does not exist in our records", None))
|
||||
},
|
||||
Self::FileNotAvailable => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File not available", None))
|
||||
}
|
||||
Self::DisputeStatusValidationFailed { .. } => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "Dispute status validation failed", None))
|
||||
}
|
||||
Self::FileValidationFailed { reason } => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, format!("File validation failed {reason}"), None))
|
||||
}
|
||||
Self::MissingFile => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File not found in the request", None))
|
||||
}
|
||||
Self::MissingFilePurpose => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File purpose not found in the request or is invalid", None))
|
||||
}
|
||||
Self::MissingFileContentType => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File content type not found", None))
|
||||
}
|
||||
Self::MissingDisputeId => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "Dispute id not found in the request", None))
|
||||
}
|
||||
Self::WebhookAuthenticationFailed => {
|
||||
AER::Unauthorized(ApiError::new("WE", 1, "Webhook authentication failed", None))
|
||||
}
|
||||
Self::WebhookResourceNotFound => {
|
||||
AER::NotFound(ApiError::new("WE", 4, "Webhook resource was not found", None))
|
||||
}
|
||||
Self::WebhookBadRequest => {
|
||||
AER::BadRequest(ApiError::new("WE", 2, "Bad request body received", None))
|
||||
}
|
||||
Self::WebhookProcessingFailure => {
|
||||
AER::InternalServerError(ApiError::new("WE", 3, "There was an issue processing the webhook", None))
|
||||
},
|
||||
Self::WebhookInvalidMerchantSecret => {
|
||||
AER::BadRequest(ApiError::new("WE", 2, "Merchant Secret set for webhook source verificartion is invalid", None))
|
||||
}
|
||||
Self::IncorrectPaymentMethodConfiguration => {
|
||||
AER::BadRequest(ApiError::new("HE", 4, "No eligible connector was found for the current payment method configuration", None))
|
||||
}
|
||||
Self::WebhookUnprocessableEntity => {
|
||||
AER::Unprocessable(ApiError::new("WE", 5, "There was an issue processing the webhook body", None))
|
||||
},
|
||||
Self::ResourceBusy => {
|
||||
AER::Unprocessable(ApiError::new("WE", 5, "There was an issue processing the webhook body", None))
|
||||
}
|
||||
Self::PaymentLinkNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment Link does not exist in our records", None))
|
||||
}
|
||||
Self::InvalidConnectorConfiguration {config} => {
|
||||
AER::BadRequest(ApiError::new("IR", 24, format!("Merchant connector account is configured with invalid {config}"), None))
|
||||
}
|
||||
Self::CurrencyConversionFailed => {
|
||||
AER::Unprocessable(ApiError::new("HE", 2, "Failed to convert currency to minor unit", None))
|
||||
}
|
||||
Self::PaymentMethodDeleteFailed => {
|
||||
AER::BadRequest(ApiError::new("IR", 25, "Cannot delete the default payment method", None))
|
||||
}
|
||||
Self::InvalidCookie => {
|
||||
AER::BadRequest(ApiError::new("IR", 26, "Invalid Cookie", None))
|
||||
}
|
||||
Self::ExtendedCardInfoNotFound => {
|
||||
AER::NotFound(ApiError::new("IR", 27, "Extended card info does not exist", None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
use super::{ConnectorError, CustomersErrorResponse, StorageError};
|
||||
|
||||
impl ErrorSwitch<ApiErrorResponse> for ConnectorError {
|
||||
fn switch(&self) -> ApiErrorResponse {
|
||||
|
||||
@ -158,9 +158,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
|
||||
}
|
||||
errors::ConnectorError::NotImplemented(reason) => {
|
||||
errors::ApiErrorResponse::NotImplemented {
|
||||
message: errors::api_error_response::NotImplementedMessage::Reason(
|
||||
reason.to_string(),
|
||||
),
|
||||
message: errors::NotImplementedMessage::Reason(reason.to_string()),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
@ -249,7 +247,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
|
||||
}
|
||||
errors::ConnectorError::NotImplemented(reason) => {
|
||||
errors::ApiErrorResponse::NotImplemented {
|
||||
message: errors::api_error_response::NotImplementedMessage::Reason(
|
||||
message: errors::NotImplementedMessage::Reason(
|
||||
reason.to_string(),
|
||||
),
|
||||
}
|
||||
@ -476,9 +474,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
|
||||
}
|
||||
errors::ConnectorError::NotImplemented(reason) => {
|
||||
errors::ApiErrorResponse::NotImplemented {
|
||||
message: errors::api_error_response::NotImplementedMessage::Reason(
|
||||
reason.to_string(),
|
||||
),
|
||||
message: errors::NotImplementedMessage::Reason(reason.to_string()),
|
||||
}
|
||||
}
|
||||
_ => errors::ApiErrorResponse::InternalServerError,
|
||||
|
||||
@ -5,20 +5,20 @@ use api_models::{
|
||||
refunds::RefundResponse,
|
||||
};
|
||||
use common_enums::FrmSuggestion;
|
||||
use common_utils::pii::{Email, SecretSerdeValue};
|
||||
use common_utils::pii::SecretSerdeValue;
|
||||
use hyperswitch_domain_models::payments::{payment_attempt::PaymentAttempt, PaymentIntent};
|
||||
pub use hyperswitch_domain_models::router_request_types::fraud_check::{
|
||||
Address, Destination, FrmFulfillmentRequest, FulfillmentStatus, Fulfillments, Product,
|
||||
};
|
||||
use masking::Serialize;
|
||||
use serde::Deserialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use super::operation::BoxedFraudCheckOperation;
|
||||
use crate::{
|
||||
pii::Secret,
|
||||
types::{
|
||||
domain::MerchantAccount,
|
||||
storage::{enums as storage_enums, fraud_check::FraudCheck},
|
||||
PaymentAddress,
|
||||
},
|
||||
use crate::types::{
|
||||
domain::MerchantAccount,
|
||||
storage::{enums as storage_enums, fraud_check::FraudCheck},
|
||||
PaymentAddress,
|
||||
};
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
@ -106,98 +106,6 @@ pub struct FrmFulfillmentSignifydApiRequest {
|
||||
pub fulfillments: Vec<Fulfillments>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, ToSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct FrmFulfillmentRequest {
|
||||
///unique payment_id for the transaction
|
||||
#[schema(max_length = 255, example = "pay_qiYfHcDou1ycIaxVXKHF")]
|
||||
pub payment_id: String,
|
||||
///unique order_id for the order_details in the transaction
|
||||
#[schema(max_length = 255, example = "pay_qiYfHcDou1ycIaxVXKHF")]
|
||||
pub order_id: String,
|
||||
///denotes the status of the fulfillment... can be one of PARTIAL, COMPLETE, REPLACEMENT, CANCELED
|
||||
#[schema(value_type = Option<FulfillmentStatus>, example = "COMPLETE")]
|
||||
pub fulfillment_status: Option<FulfillmentStatus>,
|
||||
///contains details of the fulfillment
|
||||
#[schema(value_type = Vec<Fulfillments>)]
|
||||
pub fulfillments: Vec<Fulfillments>,
|
||||
//name of the tracking Company
|
||||
#[schema(max_length = 255, example = "fedex")]
|
||||
pub tracking_company: Option<String>,
|
||||
//tracking ID of the product
|
||||
#[schema(example = r#"["track_8327446667", "track_8327446668"]"#)]
|
||||
pub tracking_numbers: Option<Vec<String>>,
|
||||
//tracking_url for tracking the product
|
||||
pub tracking_urls: Option<Vec<String>>,
|
||||
// The name of the Shipper.
|
||||
pub carrier: Option<String>,
|
||||
// Fulfillment method for the shipment.
|
||||
pub fulfillment_method: Option<String>,
|
||||
// Statuses to indicate shipment state.
|
||||
pub shipment_status: Option<String>,
|
||||
// The date and time items are ready to be shipped.
|
||||
pub shipped_at: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Fulfillments {
|
||||
///shipment_id of the shipped items
|
||||
#[schema(max_length = 255, example = "ship_101")]
|
||||
pub shipment_id: String,
|
||||
///products sent in the shipment
|
||||
#[schema(value_type = Option<Vec<Product>>)]
|
||||
pub products: Option<Vec<Product>>,
|
||||
///destination address of the shipment
|
||||
#[schema(value_type = Destination)]
|
||||
pub destination: Destination,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(untagged)]
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum FulfillmentStatus {
|
||||
PARTIAL,
|
||||
COMPLETE,
|
||||
REPLACEMENT,
|
||||
CANCELED,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Product {
|
||||
pub item_name: String,
|
||||
pub item_quantity: i64,
|
||||
pub item_id: String,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)]
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Destination {
|
||||
pub full_name: Secret<String>,
|
||||
pub organization: Option<String>,
|
||||
pub email: Option<Email>,
|
||||
pub address: Address,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Eq, PartialEq, Deserialize, Clone)]
|
||||
#[serde_with::skip_serializing_none]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Address {
|
||||
pub street_address: Secret<String>,
|
||||
pub unit: Option<Secret<String>>,
|
||||
pub postal_code: Secret<String>,
|
||||
pub city: String,
|
||||
pub province_code: Secret<String>,
|
||||
pub country_code: common_enums::CountryAlpha2,
|
||||
}
|
||||
|
||||
#[derive(Debug, ToSchema, Clone, Serialize)]
|
||||
pub struct FrmFulfillmentResponse {
|
||||
///unique order_id for the transaction
|
||||
|
||||
@ -34,10 +34,11 @@ use error_stack::{report, ResultExt};
|
||||
use events::EventInfo;
|
||||
use futures::future::join_all;
|
||||
use helpers::ApplePayData;
|
||||
use hyperswitch_domain_models::{
|
||||
pub use hyperswitch_domain_models::{
|
||||
mandates::{CustomerAcceptance, MandateData},
|
||||
payment_address::PaymentAddress,
|
||||
router_data::RouterData,
|
||||
router_request_types::CustomerDetails,
|
||||
};
|
||||
use masking::{ExposeInterface, Secret};
|
||||
use redis_interface::errors::RedisError;
|
||||
@ -2488,15 +2489,6 @@ pub struct IncrementalAuthorizationDetails {
|
||||
pub authorization_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct CustomerDetails {
|
||||
pub customer_id: Option<String>,
|
||||
pub name: Option<Secret<String, masking::WithType>>,
|
||||
pub email: Option<pii::Email>,
|
||||
pub phone: Option<Secret<String, masking::WithType>>,
|
||||
pub phone_country_code: Option<String>,
|
||||
}
|
||||
|
||||
pub trait CustomerDetailsExt {
|
||||
type Error;
|
||||
fn get_name(&self) -> Result<Secret<String, masking::WithType>, Self::Error>;
|
||||
|
||||
@ -3,7 +3,7 @@ use async_trait::async_trait;
|
||||
use super::{ConstructFlowSpecificData, Feature};
|
||||
use crate::{
|
||||
core::{
|
||||
errors::{api_error_response::NotImplementedMessage, ApiErrorResponse, RouterResult},
|
||||
errors::{ApiErrorResponse, NotImplementedMessage, RouterResult},
|
||||
payments::{self, access_token, helpers, transformers, PaymentData},
|
||||
},
|
||||
routes::AppState,
|
||||
|
||||
@ -3,7 +3,7 @@ use async_trait::async_trait;
|
||||
use super::{ConstructFlowSpecificData, Feature};
|
||||
use crate::{
|
||||
core::{
|
||||
errors::{api_error_response::NotImplementedMessage, ApiErrorResponse, RouterResult},
|
||||
errors::{ApiErrorResponse, NotImplementedMessage, RouterResult},
|
||||
payments::{self, access_token, helpers, transformers, PaymentData},
|
||||
},
|
||||
routes::AppState,
|
||||
|
||||
@ -150,7 +150,7 @@ where
|
||||
}
|
||||
api_models::gsm::GsmDecision::Requeue => {
|
||||
Err(report!(errors::ApiErrorResponse::NotImplemented {
|
||||
message: errors::api_error_response::NotImplementedMessage::Reason(
|
||||
message: errors::NotImplementedMessage::Reason(
|
||||
"Requeue not implemented".to_string(),
|
||||
),
|
||||
}))?
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use std::{collections::HashMap, num::TryFromIntError};
|
||||
|
||||
use api_models::{payment_methods::SurchargeDetailsResponse, payments::RequestSurchargeDetails};
|
||||
use api_models::payment_methods::SurchargeDetailsResponse;
|
||||
use common_utils::{
|
||||
consts,
|
||||
errors::CustomResult,
|
||||
ext_traits::{Encode, OptionExt},
|
||||
types as common_types,
|
||||
@ -10,6 +9,7 @@ use common_utils::{
|
||||
use diesel_models::business_profile::BusinessProfile;
|
||||
use error_stack::ResultExt;
|
||||
use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt;
|
||||
pub use hyperswitch_domain_models::router_request_types::{AuthenticationData, SurchargeDetails};
|
||||
use redis_interface::errors::RedisError;
|
||||
use router_env::{instrument, tracing};
|
||||
|
||||
@ -186,40 +186,6 @@ impl MultipleCaptureData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct SurchargeDetails {
|
||||
/// original_amount
|
||||
pub original_amount: common_types::MinorUnit,
|
||||
/// surcharge value
|
||||
pub surcharge: common_types::Surcharge,
|
||||
/// tax on surcharge value
|
||||
pub tax_on_surcharge:
|
||||
Option<common_types::Percentage<{ consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH }>>,
|
||||
/// surcharge amount for this payment
|
||||
pub surcharge_amount: common_types::MinorUnit,
|
||||
/// tax on surcharge amount for this payment
|
||||
pub tax_on_surcharge_amount: common_types::MinorUnit,
|
||||
/// sum of original amount,
|
||||
pub final_amount: common_types::MinorUnit,
|
||||
}
|
||||
|
||||
impl From<(&RequestSurchargeDetails, &PaymentAttempt)> for SurchargeDetails {
|
||||
fn from(
|
||||
(request_surcharge_details, payment_attempt): (&RequestSurchargeDetails, &PaymentAttempt),
|
||||
) -> Self {
|
||||
let surcharge_amount = request_surcharge_details.surcharge_amount;
|
||||
let tax_on_surcharge_amount = request_surcharge_details.tax_amount.unwrap_or_default();
|
||||
Self {
|
||||
original_amount: payment_attempt.amount,
|
||||
surcharge: common_types::Surcharge::Fixed(request_surcharge_details.surcharge_amount), // need to check this
|
||||
tax_on_surcharge: None,
|
||||
surcharge_amount,
|
||||
tax_on_surcharge_amount,
|
||||
final_amount: payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignTryFrom<(&SurchargeDetails, &PaymentAttempt)> for SurchargeDetailsResponse {
|
||||
type Error = TryFromIntError;
|
||||
fn foreign_try_from(
|
||||
@ -250,20 +216,6 @@ impl ForeignTryFrom<(&SurchargeDetails, &PaymentAttempt)> for SurchargeDetailsRe
|
||||
}
|
||||
}
|
||||
|
||||
impl SurchargeDetails {
|
||||
pub fn is_request_surcharge_matching(
|
||||
&self,
|
||||
request_surcharge_details: RequestSurchargeDetails,
|
||||
) -> bool {
|
||||
request_surcharge_details.surcharge_amount == self.surcharge_amount
|
||||
&& request_surcharge_details.tax_amount.unwrap_or_default()
|
||||
== self.tax_on_surcharge_amount
|
||||
}
|
||||
pub fn get_total_surcharge_amount(&self) -> common_types::MinorUnit {
|
||||
self.surcharge_amount + self.tax_on_surcharge_amount
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, Clone, Debug, strum::Display)]
|
||||
pub enum SurchargeKey {
|
||||
Token(String),
|
||||
@ -387,14 +339,6 @@ impl SurchargeMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AuthenticationData {
|
||||
pub eci: Option<String>,
|
||||
pub cavv: String,
|
||||
pub threeds_server_transaction_id: String,
|
||||
pub message_version: String,
|
||||
}
|
||||
|
||||
impl ForeignTryFrom<&storage::Authentication> for AuthenticationData {
|
||||
type Error = error_stack::Report<errors::ApiErrorResponse>;
|
||||
fn foreign_try_from(authentication: &storage::Authentication) -> Result<Self, Self::Error> {
|
||||
|
||||
@ -81,7 +81,7 @@ pub async fn do_gsm_multiple_connector_actions(
|
||||
}
|
||||
api_models::gsm::GsmDecision::Requeue => {
|
||||
Err(report!(errors::ApiErrorResponse::NotImplemented {
|
||||
message: errors::api_error_response::NotImplementedMessage::Reason(
|
||||
message: errors::NotImplementedMessage::Reason(
|
||||
"Requeue not implemented".to_string(),
|
||||
),
|
||||
}))?
|
||||
@ -145,7 +145,7 @@ pub async fn do_gsm_single_connector_actions(
|
||||
}
|
||||
api_models::gsm::GsmDecision::Requeue => {
|
||||
Err(report!(errors::ApiErrorResponse::NotImplemented {
|
||||
message: errors::api_error_response::NotImplementedMessage::Reason(
|
||||
message: errors::NotImplementedMessage::Reason(
|
||||
"Requeue not implemented".to_string(),
|
||||
),
|
||||
}))?
|
||||
|
||||
@ -4,7 +4,7 @@ use common_utils::{errors::CustomResult, request::RequestContent};
|
||||
use error_stack::ResultExt;
|
||||
use masking::ExposeInterface;
|
||||
|
||||
use crate::{core::errors::api_error_response, headers, logger, routes::AppState, services};
|
||||
use crate::{core::errors, headers, logger, routes::AppState, services};
|
||||
|
||||
const APPLEPAY_INTERNAL_MERCHANT_NAME: &str = "Applepay_merchant";
|
||||
|
||||
@ -12,10 +12,8 @@ pub async fn verify_merchant_creds_for_applepay(
|
||||
state: AppState,
|
||||
body: verifications::ApplepayMerchantVerificationRequest,
|
||||
merchant_id: String,
|
||||
) -> CustomResult<
|
||||
services::ApplicationResponse<ApplepayMerchantResponse>,
|
||||
api_error_response::ApiErrorResponse,
|
||||
> {
|
||||
) -> CustomResult<services::ApplicationResponse<ApplepayMerchantResponse>, errors::ApiErrorResponse>
|
||||
{
|
||||
let applepay_merchant_configs = state.conf.applepay_merchant_configs.get_inner();
|
||||
|
||||
let applepay_internal_merchant_identifier = applepay_merchant_configs
|
||||
@ -55,7 +53,7 @@ pub async fn verify_merchant_creds_for_applepay(
|
||||
utils::log_applepay_verification_response_if_error(&response);
|
||||
|
||||
let applepay_response =
|
||||
response.change_context(api_error_response::ApiErrorResponse::InternalServerError)?;
|
||||
response.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
|
||||
// Error is already logged
|
||||
match applepay_response {
|
||||
@ -67,7 +65,7 @@ pub async fn verify_merchant_creds_for_applepay(
|
||||
body.domain_names.clone(),
|
||||
)
|
||||
.await
|
||||
.change_context(api_error_response::ApiErrorResponse::InternalServerError)?;
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
Ok(services::api::ApplicationResponse::Json(
|
||||
ApplepayMerchantResponse {
|
||||
status_message: "Applepay verification Completed".to_string(),
|
||||
@ -76,7 +74,7 @@ pub async fn verify_merchant_creds_for_applepay(
|
||||
}
|
||||
Err(error) => {
|
||||
logger::error!(?error);
|
||||
Err(api_error_response::ApiErrorResponse::InvalidRequestData {
|
||||
Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "Applepay verification Failed".to_string(),
|
||||
}
|
||||
.into())
|
||||
@ -90,13 +88,13 @@ pub async fn get_verified_apple_domains_with_mid_mca_id(
|
||||
merchant_connector_id: String,
|
||||
) -> CustomResult<
|
||||
services::ApplicationResponse<verifications::ApplepayVerifiedDomainsResponse>,
|
||||
api_error_response::ApiErrorResponse,
|
||||
errors::ApiErrorResponse,
|
||||
> {
|
||||
let db = state.store.as_ref();
|
||||
let key_store = db
|
||||
.get_merchant_key_store_by_merchant_id(&merchant_id, &db.get_master_key().to_vec().into())
|
||||
.await
|
||||
.change_context(api_error_response::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
.change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let verified_domains = db
|
||||
.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
|
||||
@ -105,7 +103,7 @@ pub async fn get_verified_apple_domains_with_mid_mca_id(
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.change_context(api_error_response::ApiErrorResponse::ResourceIdNotFound)?
|
||||
.change_context(errors::ApiErrorResponse::ResourceIdNotFound)?
|
||||
.applepay_verified_domains
|
||||
.unwrap_or_default();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user