Skip to main content

comdirect_rest_api/accounts/
types.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::BTreeMap;
4
5/// API response for `/banking/clients/user/v2/accounts/balances`.
6#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7pub struct AccountBalancesResponse {
8    #[serde(default)]
9    pub values: Vec<AccountBalance>,
10}
11
12/// One account balance entry returned by the accounts endpoint.
13#[derive(Debug, Clone, Serialize, Deserialize, Default)]
14#[serde(rename_all = "camelCase")]
15pub struct AccountBalance {
16    pub account: Option<AccountDetails>,
17    pub account_id: Option<String>,
18    pub balance: Option<BalanceAmount>,
19    pub balance_eur: Option<BalanceAmount>,
20    pub available_cash_amount: Option<BalanceAmount>,
21    pub available_cash_amount_eur: Option<BalanceAmount>,
22    #[serde(flatten)]
23    pub extra: BTreeMap<String, Value>,
24}
25
26/// Generic amount shape used by account payloads.
27#[derive(Debug, Clone, Serialize, Deserialize, Default)]
28pub struct BalanceAmount {
29    pub value: Option<String>,
30    pub unit: Option<String>,
31}
32
33/// Account metadata object.
34#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35#[serde(rename_all = "camelCase")]
36pub struct AccountDetails {
37    pub account_id: Option<String>,
38    pub account_display_id: Option<String>,
39    pub currency: Option<String>,
40    pub client_id: Option<String>,
41    pub account_type: Option<AccountType>,
42    pub iban: Option<String>,
43    pub bic: Option<String>,
44    pub credit_limit: Option<BalanceAmount>,
45    #[serde(flatten)]
46    pub extra: BTreeMap<String, Value>,
47}
48
49/// Key-text pair for account type fields.
50#[derive(Debug, Clone, Serialize, Deserialize, Default)]
51pub struct AccountType {
52    pub key: Option<String>,
53    pub text: Option<String>,
54}
55
56/// API response for `/banking/v1/accounts/{account_id}/transactions`.
57#[derive(Debug, Clone, Serialize, Deserialize, Default)]
58pub struct AccountTransactionsResponse {
59    pub paging: Option<Paging>,
60    pub aggregated: Option<AccountTransactionAggregate>,
61    #[serde(default)]
62    pub values: Vec<AccountTransaction>,
63}
64
65/// Common paging object returned by account endpoints.
66#[derive(Debug, Clone, Serialize, Deserialize, Default)]
67pub struct Paging {
68    pub index: Option<u32>,
69    pub matches: Option<u32>,
70}
71
72/// Aggregated transaction metadata for one account.
73#[derive(Debug, Clone, Serialize, Deserialize, Default)]
74#[serde(rename_all = "camelCase")]
75pub struct AccountTransactionAggregate {
76    pub account: Option<AccountDetails>,
77    pub account_id: Option<String>,
78    pub booking_date_latest_transaction: Option<String>,
79    pub booking_date_oldest_transaction: Option<String>,
80    pub reference_latest_transaction: Option<String>,
81    pub reference_oldest_transaction: Option<String>,
82    pub latest_transaction_included: Option<bool>,
83    pub paging_timestamp: Option<String>,
84    pub amount_sum: Option<BalanceAmount>,
85    pub amount_count: Option<u64>,
86    #[serde(flatten)]
87    pub extra: BTreeMap<String, Value>,
88}
89
90/// One transaction row returned by the account transactions endpoint.
91#[derive(Debug, Clone, Serialize, Deserialize, Default)]
92#[serde(rename_all = "camelCase")]
93pub struct AccountTransaction {
94    pub transaction_id: Option<String>,
95    pub reference: Option<String>,
96    pub booking_status: Option<String>,
97    pub booking_date: Option<String>,
98    pub valuta_date: Option<String>,
99    pub amount: Option<BalanceAmount>,
100    pub remitter: Option<TransactionParty>,
101    #[serde(alias = "deptor")]
102    pub debtor: Option<TransactionParty>,
103    pub creditor: Option<TransactionParty>,
104    pub direct_debit_creditor_id: Option<String>,
105    pub direct_debit_mandate_id: Option<String>,
106    pub end_to_end_reference: Option<String>,
107    pub new_transaction: Option<bool>,
108    pub remittance_info: Option<String>,
109    pub transaction_type: Option<TransactionType>,
110    #[serde(flatten)]
111    pub extra: BTreeMap<String, Value>,
112}
113
114/// Payer/payee shape used in transactions.
115#[derive(Debug, Clone, Serialize, Deserialize, Default)]
116#[serde(rename_all = "camelCase")]
117pub struct TransactionParty {
118    pub holder_name: Option<String>,
119    pub iban: Option<String>,
120    pub bic: Option<String>,
121    #[serde(flatten)]
122    pub extra: BTreeMap<String, Value>,
123}
124
125/// Key-text pair for transaction type fields.
126#[derive(Debug, Clone, Serialize, Deserialize, Default)]
127pub struct TransactionType {
128    pub key: Option<String>,
129    pub text: Option<String>,
130}
131
132#[cfg(test)]
133mod tests {
134    use super::{AccountBalancesResponse, AccountTransactionsResponse};
135
136    #[test]
137    fn balances_response_deserializes_with_optional_fields() {
138        let raw = r#"{"paging":{"index":0,"matches":1},"values":[{"account":{"accountId":"a1","accountType":{"key":"DAS","text":"Tagesgeld"}},"accountId":"a1","balance":{"value":"12.34","unit":"EUR"},"balanceEUR":{"value":"12.34","unit":"EUR"}}]}"#;
139        let parsed: AccountBalancesResponse = serde_json::from_str(raw).unwrap();
140        assert_eq!(parsed.values.len(), 1);
141        assert_eq!(parsed.values[0].account_id.as_deref(), Some("a1"));
142    }
143
144    #[test]
145    fn transactions_response_deserializes_transaction_type_object() {
146        let raw = r#"{"paging":{"index":0,"matches":1},"aggregated":{"accountId":"acc-1","bookingDateLatestTransaction":"2026-01-05"},"values":[{"reference":"r1","bookingStatus":"BOOKED","bookingDate":"2026-01-05","valutaDate":"2026-01-03","amount":{"value":"-10","unit":"EUR"},"transactionType":{"key":"TRANSFER","text":"Transfer"}}]}"#;
147        let parsed: AccountTransactionsResponse = serde_json::from_str(raw).unwrap();
148        assert_eq!(parsed.values.len(), 1);
149        let tx_type = parsed.values[0].transaction_type.as_ref().unwrap();
150        assert_eq!(tx_type.key.as_deref(), Some("TRANSFER"));
151    }
152}