types.rs (14575B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use std::collections::BTreeMap; 18 19 use jiff::Timestamp; 20 use serde::Deserialize; 21 use taler_common::types::amount::Decimal; 22 23 use crate::CyclosId; 24 25 #[derive(Debug, Deserialize, Clone)] 26 #[serde(rename_all = "camelCase")] 27 pub struct Type { 28 pub id: CyclosId, 29 pub internal_name: String, 30 pub name: String, 31 } 32 33 #[derive(Debug, Deserialize, Clone)] 34 #[serde(rename_all = "camelCase")] 35 pub struct Currency { 36 #[serde(flatten)] 37 pub ty: Type, 38 pub decimal_digits: u8, 39 pub suffix: String, 40 pub symbol: String, 41 } 42 43 #[derive(Debug, Deserialize, Clone)] 44 #[serde(rename_all = "camelCase")] 45 pub struct AccountStatus { 46 pub available_balance: Decimal, 47 pub balance: Decimal, 48 pub credit_limit: Decimal, 49 pub reserved_amount: Decimal, 50 } 51 52 #[derive(Debug, Deserialize, Clone)] 53 #[serde(rename_all = "camelCase")] 54 pub struct Account { 55 pub id: CyclosId, 56 pub currency: Currency, 57 pub status: AccountStatus, 58 #[serde(rename = "type")] 59 pub ty: Type, 60 } 61 62 #[derive(Debug, Deserialize)] 63 #[serde(rename_all = "camelCase")] 64 pub struct User { 65 pub id: CyclosId, 66 pub name: String, 67 } 68 69 #[derive(Debug, Deserialize)] 70 #[serde(rename_all = "camelCase")] 71 pub struct PaymentData { 72 #[serde(flatten)] 73 pub ty: Type, 74 pub currency: Currency, 75 } 76 77 #[derive(Debug, Deserialize)] 78 #[serde(rename_all = "camelCase")] 79 pub struct DataForTransaction { 80 pub payment_type_data: PaymentData, 81 } 82 83 #[derive(Debug, Deserialize)] 84 #[serde(rename_all = "camelCase")] 85 pub struct RelatedAccount { 86 pub id: CyclosId, 87 #[serde(rename = "type")] 88 pub ty: Type, 89 #[serde(flatten)] 90 pub kind: AccountKind, 91 } 92 93 #[derive(Debug, Deserialize)] 94 #[serde(rename_all = "camelCase")] 95 pub struct HistoryItem { 96 pub id: CyclosId, 97 pub date: Timestamp, 98 pub amount: String, 99 #[serde(rename = "type")] 100 pub ty: Type, 101 pub description: Option<String>, 102 pub related_account: RelatedAccount, 103 pub transaction: Option<TransactionMini> 104 } 105 106 #[derive(Debug, Deserialize)] 107 #[serde(rename_all = "camelCase")] 108 pub struct TransferView { 109 pub id: CyclosId, 110 pub date: Timestamp, 111 pub amount: Decimal, 112 #[serde(rename = "type")] 113 pub ty: Type, 114 } 115 116 #[derive(Debug, Deserialize)] 117 #[serde(rename_all = "camelCase")] 118 pub struct Transfer { 119 pub id: CyclosId, 120 pub date: Timestamp, 121 pub amount: Decimal, 122 pub can_chargeback: bool, 123 pub kind: TransferKind, 124 pub currency: Currency, 125 pub chargeback_of: Option<TransferView>, 126 pub chargeback_by: Option<TransferView>, 127 #[serde(rename = "type")] 128 pub ty: Type, 129 } 130 131 #[derive(Debug, Deserialize)] 132 #[serde(rename_all = "camelCase")] 133 pub struct Transaction { 134 pub id: CyclosId, 135 pub date: Timestamp, 136 pub amount: Decimal, 137 pub kind: TxKind, 138 pub currency: Currency, 139 #[serde(rename = "type")] 140 pub ty: Type, 141 } 142 143 #[derive(Debug, Deserialize)] 144 #[serde(rename_all = "camelCase")] 145 pub struct TransactionMini { 146 pub id: CyclosId, 147 pub kind: TxKind, 148 } 149 150 #[derive(Debug, serde::Deserialize)] 151 #[serde(rename_all = "camelCase")] 152 /// Indicates the reason the transfer was created. 153 pub enum TransferKind { 154 /// A transfer generated by an account fee charge 155 AccountFee, 156 /// A transfer which either withdraws or credits funds of an account being disposed 157 BalanceDisposal, 158 /// A transfer which is a chargeback of another transfer 159 Chargeback, 160 /// An imported transfer 161 Import, 162 /// A transfer which is the initial credit for a newly created account 163 InitialCredit, 164 /// A transfer generated when processing a scheduled / recurring payment installment / occurrence 165 Installment, 166 /// A transfer generated by a direct payment or accepting a webshop order 167 Payment, 168 /// A transfer generated by a transfer fee charge 169 TransferFee, 170 } 171 172 #[derive(Debug, serde::Deserialize)] 173 #[serde(rename_all = "camelCase")] 174 pub enum TxKind { 175 Chargeback, 176 ExternalPayment, 177 Import, 178 Order, 179 Payment, 180 PaymentRequest, 181 RecurringPayment, 182 ScheduledPayment, 183 Ticket, 184 } 185 186 #[derive(Debug, serde::Deserialize)] 187 #[serde(rename_all = "camelCase")] 188 pub enum InvalidDeviceConfirmation { 189 InvalidConfirmation, 190 InvalidDevice, 191 MaxCheckAtemptsReached, 192 } 193 194 #[derive(Debug, serde::Deserialize)] 195 #[serde(rename_all = "camelCase")] 196 pub struct UserInfo { 197 pub id: CyclosId, 198 pub display: String, 199 } 200 201 #[derive(Debug, serde::Deserialize)] 202 #[serde(rename_all = "camelCase")] 203 #[serde(tag = "kind")] 204 pub enum AccountKind { 205 System, 206 User { user: UserInfo }, 207 } 208 209 #[derive(Debug, serde::Deserialize)] 210 #[serde(rename_all = "camelCase")] 211 pub enum UserStatus { 212 Active, 213 Blocked, 214 Disabled, 215 Pending, 216 Purged, 217 Removed, 218 } 219 220 #[derive(Debug, serde::Deserialize)] 221 #[serde(rename_all = "camelCase")] 222 pub enum PasswordStatus { 223 Active, 224 Disabled, 225 Expired, 226 IndefinitelyBlocked, 227 NeverCreated, 228 Pending, 229 Reset, 230 TemporarilyBlocked, 231 } 232 233 #[derive(Debug, serde::Deserialize, thiserror::Error)] 234 #[serde(tag = "code", rename_all = "camelCase")] 235 pub enum UnauthorizedError { 236 #[error("blockedAccessClient - The access client used for access is blocked")] 237 BlockedAccessClient, 238 #[error("invalidAccessClient - The access client used for access is invalid")] 239 InvalidAccessClient, 240 #[error( 241 "invalidAccessToken '{error}' - The OAuth2 / OpenID Connect access token used for access is invalid" 242 )] 243 InvalidAccessToken { error: String }, 244 #[error( 245 "invalidChannelUsage - Attempt to login on a stateless-only channel, or use stateless in a stateful-only channel, or invoke as guest in a channel configuration which is only for users" 246 )] 247 InvalidChannelUsage, 248 #[error( 249 "invalidNetwork - Attempt to access a network that has been disabled, or a restricted global administrator is trying to login to a inaccessible network" 250 )] 251 InvalidNetwork, 252 #[error("loggedOut - The session token used for access is invalid")] 253 LoggedOut, 254 #[error( 255 "login {invalid_device_confirmation:?} {user_status:?} {pasword_status:?} - Either user identification (principal) or password are invalid. May have additional information, such as the user / password status" 256 )] 257 #[serde(rename = "camelCase")] 258 Login { 259 invalid_device_confirmation: InvalidDeviceConfirmation, 260 user_status: UserStatus, 261 pasword_status: PasswordStatus, 262 }, 263 #[error( 264 "missingAuthorization - Attempt to access an operation as guest, but the operation requires authentication" 265 )] 266 MissingAuthorization, 267 #[error( 268 "remoteAddressBlocked - The IP address being used for access has been blocked by exceeding tries with invalid users" 269 )] 270 RemoteAddressBlocked, 271 #[error( 272 "unauthorizedAddress - The user cannot access the system using an IP address that is not white-listed" 273 )] 274 UnauthorizedAddress, 275 #[error( 276 "unauthorizedUrl - The user's configuration demands access using a specific URL, and this access is being done using another one" 277 )] 278 UnauthorizedUrl, 279 } 280 281 #[derive(Debug, serde::Deserialize, thiserror::Error)] 282 #[serde(tag = "code", rename_all = "camelCase")] 283 /// Error codes for 403 Forbidden HTTP status. 284 pub enum ForbiddenError { 285 #[error("blockedByTotp - The user was blocked for exceeding the TOTP attempts")] 286 BlockedByTotp, 287 #[error("devicePinRemoved - The device pin was removed by exceeding the allowed attempts")] 288 DevicePinRemoved, 289 #[error("disabledPassword - The password being used was disabled")] 290 DisabledPassword, 291 #[error("expiredPassword - The password being used has expired")] 292 ExpiredPassword, 293 #[error("illegalAction - Attempt to perform an action that is not allowed on this context")] 294 IllegalAction, 295 #[error("inaccessibleChannel - This channel cannot be accessed by the user")] 296 InaccessibleChannel, 297 #[error( 298 "inaccessibleGroup - An administrator logging in another user which is not of the managed groups. Should be handled generically, in case more group-specific login restrictions are added to Cyclos" 299 )] 300 InaccessibleGroup, 301 #[error( 302 "inaccessibleNetwork - A restricted global administrator is trying to login to a network they can't access" 303 )] 304 InaccessibleNetwork, 305 #[error( 306 "inaccessiblePrincipal - The used identification method (principal type) cannot be used in this channel" 307 )] 308 InaccessiblePrincipal, 309 #[error( 310 "indefinitelyBlocked - The password was indefinitely blocked by exceeding the allowed attempts" 311 )] 312 IndefinitelyBlocked, 313 #[error("invalidDeviceActivationCode - The device activation code was no valid")] 314 InvalidDeviceActivationCode, 315 #[error( 316 "invalidDeviceConfirmation - The device confirmation being used is invalid (normally as a confirmation password)" 317 )] 318 InvalidDeviceConfirmation, 319 #[error( 320 "invalidPassword - The password being used is invalid (normally the confirmation password)" 321 )] 322 InvalidPassword, 323 #[error("invalidTotp - A given TOTP is invalid")] 324 InvalidTotp, 325 #[error("loginConfirmation - The user needs to confirm the login before proceeding")] 326 LoginConfirmation, 327 #[error( 328 "operatorWithPendingAgreements - The operator cannot access because his owner member has pending agreements" 329 )] 330 OperatorWithPendingAgreements, 331 #[error("otpInvalidated - The OTP was invalidated")] 332 OtpInvalidated, 333 #[error( 334 "pendingAgreements - There is at least one agreement which needs to be accepted in order to access the system" 335 )] 336 PendingAgreements, 337 #[error( 338 "permissionDenied - The operation was denied because a required permission was not granted" 339 )] 340 PermissionDenied, 341 #[error("resetPassword - The password being used was manually reset")] 342 ResetPassword, 343 #[error( 344 "temporarilyBlocked - The password was temporarily blocked by exceeding the allowed attempts" 345 )] 346 TemporarilyBlocked, 347 } 348 349 #[derive(Debug, serde::Deserialize, thiserror::Error)] 350 #[serde(tag = "code", rename_all = "camelCase")] 351 /// Error codes for 404 Service Unavailable entity HTTP status. It means that some required service couldn't be contacted 352 pub enum UnavailableError { 353 #[error("emailSending - An error has occurred trying to send the a required email")] 354 Emailsending, 355 #[error("smsSending - An error has occurred trying to send a required SMS message")] 356 Smssending, 357 } 358 359 #[derive(Debug, serde::Deserialize, thiserror::Error)] 360 #[serde(tag = "code", rename_all = "camelCase")] 361 #[error("{entity_type} {key}")] 362 /// Error codes for 404 Not Found 363 pub struct NotFoundError { 364 pub entity_type: String, 365 pub key: String, 366 } 367 368 #[derive(Debug, serde::Deserialize, thiserror::Error)] 369 #[serde(tag = "code", rename_all = "camelCase")] 370 /// Error types associated to the HTTP Status 500. 371 pub enum UnexpectedError { 372 #[error("buyVoucher - An error has occurred when buying a voucher")] 373 BuyVoucher, 374 #[error("forgottenPassword - An error has occurred when changing a forgotten password")] 375 ForgottenPassword, 376 #[error("general - An unexpected error has occurred")] 377 General, 378 #[error("initializeNfc - An error has occurred when initializing a NFC token")] 379 InitializeNfc, 380 #[error("nested - An error which has another internal error at a given property / index")] 381 Nested, 382 #[error("nfcAuth - An error has occurred when making an external NFC authentication")] 383 NfcAuth, 384 #[error("oidc - An error for an OpenID Connect / OAuth 2 operation")] 385 Oidc, 386 #[error("payment - An error has occurred when making a payment")] 387 Payment, 388 #[error("personalizeNfc - An error has occurred when personalizing a NFC token")] 389 PersonalizeNfc, 390 #[error("pos - An error has occurred when receiving a payment on a POS operation")] 391 Pos, 392 #[error("redeemVoucher - An error has occurred when redeeming a voucher")] 393 RedeemVoucher, 394 #[error("shoppingCart - An error has occurred when interacting with a shopping cart")] 395 ShoppingCart, 396 #[error("shoppingCartCheckout - An error has occurred when checking out a shopping cart")] 397 ShoppingCartCheckout, 398 #[error("topUpVoucher - An error has occurred on a voucher top-up")] 399 TopUpVoucher, 400 } 401 402 #[derive(Debug, serde::Deserialize, thiserror::Error)] 403 #[serde(tag = "code", rename_all = "camelCase")] 404 /// Error codes for 422 Unprocessable entity HTTP status. It means there was an error with the input sent to the operation. 405 pub enum InputError { 406 #[error("aggregated - Represents an aggregation of other input errors")] 407 Aggregated, 408 #[error( 409 "dataConversion {value} - Some data conversion has failed. For example, when sending a date with an invalid format" 410 )] 411 DataConversion { value: String }, 412 #[error("fileUploadSize {max_file_size} - An uploaded file size exceeds the maximum allowed")] 413 #[serde(rename_all = "camelCase")] 414 FileUploadSize { max_file_size: usize }, 415 #[error( 416 "maxItems {max_items} - There was an attempt to create an item, but the maximum number of allowed items was exceeded" 417 )] 418 #[serde(rename_all = "camelCase")] 419 MaxItems { max_items: usize }, 420 #[error("missingParameter {name} - Missing a required request parameter")] 421 MissingParameter { name: String }, 422 #[error("queryParse {value} - A full-text query keywords contained an invalid text")] 423 QueryParse { value: String }, 424 #[error( 425 "validation {general_errors:?} {property_errors:?} - One or more of the fields sent contains invalid values" 426 )] 427 #[serde(rename_all = "camelCase")] 428 Validation { 429 #[serde(default)] 430 general_errors: Vec<String>, 431 #[serde(default)] 432 properties: Vec<String>, 433 #[serde(default)] 434 property_errors: BTreeMap<String, Vec<String>>, 435 }, 436 }