comdirect_rest_api/accounts/
types.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7pub struct AccountBalancesResponse {
8 #[serde(default)]
9 pub values: Vec<AccountBalance>,
10}
11
12#[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#[derive(Debug, Clone, Serialize, Deserialize, Default)]
28pub struct BalanceAmount {
29 pub value: Option<String>,
30 pub unit: Option<String>,
31}
32
33#[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#[derive(Debug, Clone, Serialize, Deserialize, Default)]
51pub struct AccountType {
52 pub key: Option<String>,
53 pub text: Option<String>,
54}
55
56#[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#[derive(Debug, Clone, Serialize, Deserialize, Default)]
67pub struct Paging {
68 pub index: Option<u32>,
69 pub matches: Option<u32>,
70}
71
72#[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#[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#[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#[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}