1use crate::{CountryCode, CurrencyCode, PaymentProvider};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct ProviderErrorDetails {
6 pub provider: PaymentProvider,
8 pub status: u16,
10 pub code: Option<String>,
12 pub request_id: Option<String>,
14 pub message: String,
16}
17
18#[derive(Debug, thiserror::Error)]
20#[non_exhaustive]
21pub enum PaymentError {
22 #[error("invalid amount: {0}")]
24 InvalidAmount(i64),
25
26 #[error("invalid currency code: {0}")]
28 InvalidCurrencyCode(String),
29
30 #[error("invalid country code: {0}")]
32 InvalidCountryCode(String),
33
34 #[error("invalid reference: {0}")]
36 InvalidReference(String),
37
38 #[error("invalid idempotency key: {0}")]
40 InvalidIdempotencyKey(String),
41
42 #[error("invalid phone number")]
44 InvalidPhoneNumber(String),
45
46 #[error("invalid url: {0}")]
48 InvalidUrl(String),
49
50 #[error("missing required field: {0}")]
52 MissingRequiredField(&'static str),
53
54 #[error("invalid configuration: {0}")]
56 InvalidConfiguration(String),
57
58 #[error("connector not configured: {provider:?}")]
60 ConnectorNotConfigured { provider: PaymentProvider },
61
62 #[error("unsupported payment method: {0}")]
64 UnsupportedPaymentMethod(String),
65
66 #[error("unsupported country: {0:?}")]
68 UnsupportedCountry(CountryCode),
69
70 #[error("unsupported currency: {0:?}")]
72 UnsupportedCurrency(CurrencyCode),
73
74 #[error("unsupported payment route: method={method}, country={country:?}")]
76 UnsupportedPaymentRoute {
77 method: String,
79 country: Option<CountryCode>,
81 },
82
83 #[error("provider authentication failed")]
85 AuthenticationFailed,
86
87 #[error("provider request failed: {provider:?}, status={status}, message={message}")]
89 ProviderRequestFailed {
90 provider: PaymentProvider,
92 status: u16,
94 message: String,
96 },
97
98 #[error("provider request failed: {details:?}")]
100 ProviderDetails {
101 details: ProviderErrorDetails,
103 },
104
105 #[error("provider unavailable: {0:?}")]
107 ProviderUnavailable(PaymentProvider),
108
109 #[error("rate limited by provider: {0:?}")]
111 RateLimited(PaymentProvider),
112
113 #[error("webhook verification failed")]
115 WebhookVerificationFailed,
116
117 #[error("webhook payload invalid: {0}")]
119 InvalidWebhookPayload(String),
120
121 #[error("operation not supported: {0}")]
123 UnsupportedOperation(String),
124
125 #[error("http error: {0}")]
127 Http(#[from] reqwest::Error),
128
129 #[error("json error: {0}")]
131 Json(#[from] serde_json::Error),
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn invalid_phone_error_does_not_display_value() {
140 let error = PaymentError::InvalidPhoneNumber("+260971234567".to_owned());
141
142 assert_eq!(error.to_string(), "invalid phone number");
143 }
144}