use crate::category::Category;
use crate::response_code::{ResponseCode, ServiceCode};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("Bad Request")]
BadRequest,
#[error("Invalid Field Format {0}")]
InvalidFieldFormat(String),
#[error("Invalid Mandatory Field {0}")]
InvalidMandatoryField(String),
#[error("Unauthorized. {0}")]
Unauthorized(String),
#[error("Invalid Token (B2B)")]
InvalidTokenB2B,
#[error("Invalid Customer Token")]
InvalidCustomerToken,
#[error("Token Not Found (B2B)")]
TokenNotFoundB2B,
#[error("Customer Token Not Found")]
CustomerTokenNotFound,
#[error("Transaction Expired")]
TransactionExpired,
#[error("Feature Not Allowed {0}")]
FeatureNotAllowed(String),
#[error("Exceeds Transaction Amount Limit")]
ExceedsTransactionAmountLimit,
#[error("Suspected Fraud")]
SuspectedFraud,
#[error("Activity Count Limit Exceeded")]
ActivityCountLimitExceeded,
#[error("Do Not Honor")]
DoNotHonor,
#[error("Feature Not Allowed At This Time. {0}")]
FeatureNotAllowedAtThisTime(String),
#[error("Card Blocked")]
CardBlocked,
#[error("Card Expired")]
CardExpired,
#[error("Dormant Account")]
DormantAccount,
#[error("Need To Set Token Limit")]
NeedToSetTokenLimit,
#[error("OTP Blocked")]
OTPBlocked,
#[error("OTP Lifetime Expired")]
OTPLifetimeExpired,
#[error("OTP Sent To Cardholder")]
OTPSentToCardholder,
#[error("Insufficient Funds")]
InsufficientFunds,
#[error("Transaction Not Permitted. {0}")]
TransactionNotPermitted(String),
#[error("Suspend Transaction")]
SuspendTransaction,
#[error("Token Limit Exceeded")]
TokenLimitExceeded,
#[error("Inactive Card/Account/Customer")]
InactiveCardOrAccountOrCustomer,
#[error("Merchant Blacklisted")]
MerchantBlacklisted,
#[error("Merchant Limit Exceed")]
MerchantLimitExceed,
#[error("Set Limit Not Allowed")]
SetLimitNotAllowed,
#[error("Token Limit Invalid")]
TokenLimitInvalid,
#[error("Account Limit Exceed")]
AccountLimitExceed,
#[error("Invalid Transaction Status")]
InvalidTransactionStatus,
#[error("Transaction Not Found")]
TransactionNotFound,
#[error("Invalid Routing")]
InvalidRouting,
#[error("Bank Not Supported By Switch")]
BankNotSupportedBySwitch,
#[error("Transaction Cancelled")]
TransactionCancelled,
#[error("Merchant Is Not Registered For Card Registration Services")]
MerchantNotRegisteredForCardRegistrationServices,
#[error("Need To Request OTP")]
NeedToRequestOTP,
#[error("Journey Not Found")]
JourneyNotFound,
#[error("Invalid Merchant")]
InvalidMerchant,
#[error("No Issuer")]
NoIssuer,
#[error("Invalid API Transition")]
InvalidAPITransition,
#[error("Invalid Card/Account/Customer {0}/Virtual Account")]
InvalidCardOrAccountOrCustomerOrVirtualAccount(String),
#[error("Invalid Bill/Virtual Account {0}")]
InvalidBillOrVirtualAccountWithReason(String),
#[error("Invalid Amount")]
InvalidAmount,
#[error("Paid Bill")]
PaidBill,
#[error("Invalid OTP")]
InvalidOTP,
#[error("Partner Not Found")]
PartnerNotFound,
#[error("Invalid Terminal")]
InvalidTerminal,
#[error("Inconsistent Request")]
InconsistentRequest,
#[error("Invalid Bill/Virtual Account")]
InvalidBillOrVirtualAccount,
#[error("Requested Function Is Not Supported")]
RequestedFunctionIsNotSupported,
#[error("Requested Operation Is Not Allowed")]
RequestedOperationIsNotAllowed,
#[error("Conflict")]
Conflict,
#[error("Duplicate partnerReferenceNo")]
DuplicatePartnerReferenceNo,
#[error("Too Many Requests")]
TooManyRequests,
#[error("General Error")]
GeneralError,
#[error("Internal Server Error")]
InternalServerError,
#[error("External Server Error")]
ExternalServerError,
#[error("Timeout")]
Timeout,
#[cfg(feature = "crypto")]
#[error("crypto error: {0}")]
Crypto(#[from] kamu_snap_crypto::Error),
}
impl Error {
pub fn category(&self) -> Category {
match self {
Self::BadRequest => Category::System,
Self::InvalidFieldFormat(_) => Category::Message,
Self::InvalidMandatoryField(_) => Category::Message,
Self::Unauthorized(_) => Category::System,
Self::InvalidTokenB2B => Category::System,
Self::InvalidCustomerToken => Category::System,
Self::TokenNotFoundB2B => Category::System,
Self::CustomerTokenNotFound => Category::System,
Self::TransactionExpired => Category::Business,
Self::FeatureNotAllowed(_) => Category::System,
Self::ExceedsTransactionAmountLimit => Category::Business,
Self::SuspectedFraud => Category::Business,
Self::ActivityCountLimitExceeded => Category::Business,
Self::DoNotHonor => Category::Business,
Self::FeatureNotAllowedAtThisTime(_) => Category::System,
Self::CardBlocked => Category::Business,
Self::CardExpired => Category::Business,
Self::DormantAccount => Category::Business,
Self::NeedToSetTokenLimit => Category::Business,
Self::OTPBlocked => Category::System,
Self::OTPLifetimeExpired => Category::System,
Self::OTPSentToCardholder => Category::System,
Self::InsufficientFunds => Category::Business,
Self::TransactionNotPermitted(_) => Category::Business,
Self::SuspendTransaction => Category::Business,
Self::TokenLimitExceeded => Category::Business,
Self::InactiveCardOrAccountOrCustomer => Category::Business,
Self::MerchantBlacklisted => Category::Business,
Self::MerchantLimitExceed => Category::Business,
Self::SetLimitNotAllowed => Category::Business,
Self::TokenLimitInvalid => Category::Business,
Self::AccountLimitExceed => Category::Business,
Self::InvalidTransactionStatus => Category::Business,
Self::TransactionNotFound => Category::Business,
Self::InvalidRouting => Category::System,
Self::BankNotSupportedBySwitch => Category::System,
Self::TransactionCancelled => Category::Business,
Self::MerchantNotRegisteredForCardRegistrationServices => Category::Business,
Self::NeedToRequestOTP => Category::System,
Self::JourneyNotFound => Category::System,
Self::InvalidMerchant => Category::Business,
Self::NoIssuer => Category::Business,
Self::InvalidAPITransition => Category::System,
Self::InvalidCardOrAccountOrCustomerOrVirtualAccount(_) => Category::Business,
Self::InvalidBillOrVirtualAccountWithReason(_) => Category::Business,
Self::InvalidAmount => Category::Business,
Self::PaidBill => Category::Business,
Self::InvalidOTP => Category::System,
Self::PartnerNotFound => Category::Business,
Self::InvalidTerminal => Category::Business,
Self::InconsistentRequest => Category::Business,
Self::InvalidBillOrVirtualAccount => Category::Business,
Self::RequestedFunctionIsNotSupported => Category::System,
Self::RequestedOperationIsNotAllowed => Category::Business,
Self::Conflict => Category::System,
Self::DuplicatePartnerReferenceNo => Category::System,
Self::TooManyRequests => Category::System,
Self::GeneralError => Category::System,
Self::InternalServerError => Category::System,
Self::ExternalServerError => Category::System,
Self::Timeout => Category::System,
#[cfg(feature = "crypto")]
Self::Crypto(_) => Category::System,
}
}
pub fn http_status(&self) -> http::StatusCode {
match self {
Self::BadRequest | Self::InvalidFieldFormat(_) | Self::InvalidMandatoryField(_) => {
http::StatusCode::BAD_REQUEST
}
Self::Unauthorized(_)
| Self::InvalidTokenB2B
| Self::InvalidCustomerToken
| Self::TokenNotFoundB2B
| Self::CustomerTokenNotFound => http::StatusCode::UNAUTHORIZED,
Self::TransactionExpired
| Self::FeatureNotAllowed(_)
| Self::ExceedsTransactionAmountLimit
| Self::SuspectedFraud
| Self::ActivityCountLimitExceeded
| Self::DoNotHonor
| Self::FeatureNotAllowedAtThisTime(_)
| Self::CardBlocked
| Self::CardExpired
| Self::DormantAccount
| Self::NeedToSetTokenLimit
| Self::OTPBlocked
| Self::OTPLifetimeExpired
| Self::OTPSentToCardholder
| Self::InsufficientFunds
| Self::TransactionNotPermitted(_)
| Self::SuspendTransaction
| Self::TokenLimitExceeded
| Self::InactiveCardOrAccountOrCustomer
| Self::MerchantBlacklisted
| Self::MerchantLimitExceed
| Self::SetLimitNotAllowed
| Self::TokenLimitInvalid
| Self::AccountLimitExceed => http::StatusCode::FORBIDDEN,
Self::InvalidOTP
| Self::InvalidTransactionStatus
| Self::TransactionCancelled
| Self::MerchantNotRegisteredForCardRegistrationServices
| Self::PaidBill
| Self::PartnerNotFound
| Self::JourneyNotFound
| Self::InvalidMerchant
| Self::NoIssuer
| Self::TransactionNotFound
| Self::InconsistentRequest
| Self::InvalidAmount
| Self::InvalidAPITransition
| Self::InvalidRouting
| Self::BankNotSupportedBySwitch
| Self::InvalidTerminal
| Self::InvalidCardOrAccountOrCustomerOrVirtualAccount(_)
| Self::InvalidBillOrVirtualAccountWithReason(_)
| Self::InvalidBillOrVirtualAccount
| Self::NeedToRequestOTP => http::StatusCode::NOT_FOUND,
Self::RequestedFunctionIsNotSupported | Self::RequestedOperationIsNotAllowed => {
http::StatusCode::METHOD_NOT_ALLOWED
}
Self::Conflict | Self::DuplicatePartnerReferenceNo => http::StatusCode::CONFLICT,
Self::TooManyRequests => http::StatusCode::TOO_MANY_REQUESTS,
Self::GeneralError | Self::InternalServerError | Self::ExternalServerError => {
http::StatusCode::INTERNAL_SERVER_ERROR
}
Self::Timeout => http::StatusCode::GATEWAY_TIMEOUT,
#[cfg(feature = "crypto")]
Self::Crypto(_) => http::StatusCode::UNAUTHORIZED,
}
}
pub fn case_code(&self) -> u8 {
match self {
Self::BadRequest => 0,
Self::InvalidFieldFormat(_) => 1,
Self::InvalidMandatoryField(_) => 2,
Self::Unauthorized(_) => 0,
Self::InvalidTokenB2B => 1,
Self::InvalidCustomerToken => 2,
Self::TokenNotFoundB2B => 3,
Self::CustomerTokenNotFound => 4,
Self::TransactionExpired => 0,
Self::FeatureNotAllowed(_) => 1,
Self::ExceedsTransactionAmountLimit => 2,
Self::SuspectedFraud => 3,
Self::ActivityCountLimitExceeded => 4,
Self::DoNotHonor => 5,
Self::FeatureNotAllowedAtThisTime(_) => 6,
Self::CardBlocked => 7,
Self::CardExpired => 8,
Self::DormantAccount => 9,
Self::NeedToSetTokenLimit => 10,
Self::OTPBlocked => 11,
Self::OTPLifetimeExpired => 12,
Self::OTPSentToCardholder => 13,
Self::InsufficientFunds => 14,
Self::TransactionNotPermitted(_) => 15,
Self::SuspendTransaction => 16,
Self::TokenLimitExceeded => 17,
Self::InactiveCardOrAccountOrCustomer => 18,
Self::MerchantBlacklisted => 19,
Self::MerchantLimitExceed => 20,
Self::SetLimitNotAllowed => 21,
Self::TokenLimitInvalid => 22,
Self::AccountLimitExceed => 23,
Self::InvalidTransactionStatus => 0,
Self::TransactionNotFound => 1,
Self::InvalidRouting => 2,
Self::BankNotSupportedBySwitch => 3,
Self::TransactionCancelled => 4,
Self::MerchantNotRegisteredForCardRegistrationServices => 5,
Self::NeedToRequestOTP => 6,
Self::JourneyNotFound => 7,
Self::InvalidMerchant => 8,
Self::NoIssuer => 9,
Self::InvalidAPITransition => 10,
Self::InvalidCardOrAccountOrCustomerOrVirtualAccount(_) => 11,
Self::InvalidBillOrVirtualAccountWithReason(_) => 12,
Self::InvalidAmount => 13,
Self::PaidBill => 14,
Self::InvalidOTP => 15,
Self::PartnerNotFound => 16,
Self::InvalidTerminal => 17,
Self::InconsistentRequest => 18,
Self::InvalidBillOrVirtualAccount => 19,
Self::RequestedFunctionIsNotSupported => 0,
Self::RequestedOperationIsNotAllowed => 1,
Self::Conflict => 0,
Self::DuplicatePartnerReferenceNo => 1,
Self::TooManyRequests => 0,
Self::GeneralError => 0,
Self::InternalServerError => 1,
Self::ExternalServerError => 2,
Self::Timeout => 0,
#[cfg(feature = "crypto")]
Self::Crypto(_) => 0,
}
}
pub fn response_code(&self, service: ServiceCode) -> ResponseCode {
ResponseCode::from_parts(self.http_status().as_u16(), service, self.case_code())
}
pub fn from_http_and_case(http: u16, case: u8) -> Option<Self> {
use Error::*;
Some(match (http, case) {
(400, 0) => BadRequest,
(400, 1) => InvalidFieldFormat(String::new()),
(400, 2) => InvalidMandatoryField(String::new()),
(401, 0) => Unauthorized(String::new()),
(401, 1) => InvalidTokenB2B,
(401, 2) => InvalidCustomerToken,
(401, 3) => TokenNotFoundB2B,
(401, 4) => CustomerTokenNotFound,
(403, 0) => TransactionExpired,
(403, 1) => FeatureNotAllowed(String::new()),
(403, 2) => ExceedsTransactionAmountLimit,
(403, 3) => SuspectedFraud,
(403, 4) => ActivityCountLimitExceeded,
(403, 5) => DoNotHonor,
(403, 6) => FeatureNotAllowedAtThisTime(String::new()),
(403, 7) => CardBlocked,
(403, 8) => CardExpired,
(403, 9) => DormantAccount,
(403, 10) => NeedToSetTokenLimit,
(403, 11) => OTPBlocked,
(403, 12) => OTPLifetimeExpired,
(403, 13) => OTPSentToCardholder,
(403, 14) => InsufficientFunds,
(403, 15) => TransactionNotPermitted(String::new()),
(403, 16) => SuspendTransaction,
(403, 17) => TokenLimitExceeded,
(403, 18) => InactiveCardOrAccountOrCustomer,
(403, 19) => MerchantBlacklisted,
(403, 20) => MerchantLimitExceed,
(403, 21) => SetLimitNotAllowed,
(403, 22) => TokenLimitInvalid,
(403, 23) => AccountLimitExceed,
(404, 0) => InvalidTransactionStatus,
(404, 1) => TransactionNotFound,
(404, 2) => InvalidRouting,
(404, 3) => BankNotSupportedBySwitch,
(404, 4) => TransactionCancelled,
(404, 5) => MerchantNotRegisteredForCardRegistrationServices,
(404, 6) => NeedToRequestOTP,
(404, 7) => JourneyNotFound,
(404, 8) => InvalidMerchant,
(404, 9) => NoIssuer,
(404, 10) => InvalidAPITransition,
(404, 11) => InvalidCardOrAccountOrCustomerOrVirtualAccount(String::new()),
(404, 12) => InvalidBillOrVirtualAccountWithReason(String::new()),
(404, 13) => InvalidAmount,
(404, 14) => PaidBill,
(404, 15) => InvalidOTP,
(404, 16) => PartnerNotFound,
(404, 17) => InvalidTerminal,
(404, 18) => InconsistentRequest,
(404, 19) => InvalidBillOrVirtualAccount,
(405, 0) => RequestedFunctionIsNotSupported,
(405, 1) => RequestedOperationIsNotAllowed,
(409, 0) => Conflict,
(409, 1) => DuplicatePartnerReferenceNo,
(429, 0) => TooManyRequests,
(500, 0) => GeneralError,
(500, 1) => InternalServerError,
(500, 2) => ExternalServerError,
(504, 0) => Timeout,
_ => return None,
})
}
}