1use crate::v1::{Client, error, BASE_URL, standard};
2
3use serde::Deserialize;
4
5#[derive(Deserialize, Debug)]
8pub struct ListAccountsResponse {
9 pub data: Vec<AccountResource>,
11 pub links: ResponseLinks,
12}
13
14#[derive(Deserialize, Debug)]
15pub struct GetAccountResponse {
16 pub data: AccountResource,
18}
19
20#[derive(Deserialize, Debug)]
21pub struct AccountResource {
22 pub r#type: String,
24 pub id: String,
26 pub attributes: Attributes,
27 pub relationships: Relationships,
28 pub links: Option<AccountResourceLinks>,
29}
30
31#[derive(Deserialize, Debug)]
32pub struct AccountResourceLinks {
33 #[serde(rename = "self")]
35 pub this: Option<String>,
36}
37
38#[derive(Deserialize, Debug)]
39pub struct ResponseLinks {
40 pub prev: Option<String>,
43 pub next: Option<String>,
46}
47
48#[derive(Deserialize, Debug)]
49pub struct Relationships {
50 pub transactions: Transactions,
51}
52
53#[derive(Deserialize, Debug)]
54pub struct Transactions {
55 pub links: Option<TransactionLinks>,
56}
57
58#[derive(Deserialize, Debug)]
59pub struct TransactionLinks {
60 pub related: String,
62}
63
64#[derive(Deserialize, Debug)]
65#[serde(rename_all = "camelCase")]
66pub struct Attributes {
67 pub display_name: String,
69 pub account_type: AccountType,
72 pub ownership_type: OwnershipType,
75 pub balance: standard::MoneyObject,
78 pub created_at: String,
80}
81
82#[derive(Deserialize, Debug)]
83#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
84pub enum AccountType {
85 Saver,
86 Transactional,
87}
88
89#[derive(Deserialize, Debug)]
90#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
91pub enum OwnershipType {
92 Individual,
93 Joint,
94}
95
96#[derive(Default)]
99pub struct ListAccountsOptions {
100 page_size: Option<u8>,
102 filter_account_type: Option<String>,
105 filter_ownership_type: Option<String>,
108}
109
110impl ListAccountsOptions {
111 pub fn page_size(&mut self, value: u8) {
113 self.page_size = Some(value);
114 }
115
116 pub fn filter_account_type(&mut self, value: String) {
118 self.filter_account_type = Some(value);
119 }
120
121 pub fn filter_ownership_type(&mut self, value: String) {
123 self.filter_ownership_type = Some(value);
124 }
125
126 fn add_params(&self, url: &mut reqwest::Url) {
127 let mut query = String::new();
128
129 if let Some(value) = &self.page_size {
130 if !query.is_empty() {
131 query.push('&');
132 }
133 query.push_str(&format!("page[size]={}", value));
134 }
135
136 if let Some(value) = &self.filter_account_type {
137 if !query.is_empty() {
138 query.push('&');
139 }
140 query.push_str(
141 &format!("filter[accountType]={}", urlencoding::encode(value))
142 );
143 }
144
145 if let Some(value) = &self.filter_ownership_type {
146 if !query.is_empty() {
147 query.push('&');
148 }
149 query.push_str(
150 &format!("filter[ownershipType]={}", urlencoding::encode(value))
151 );
152 }
153
154 if !query.is_empty() {
155 url.set_query(Some(&query));
156 }
157 }
158}
159
160impl Client {
161 pub async fn list_accounts(
165 &self,
166 options: &ListAccountsOptions,
167 ) -> Result<ListAccountsResponse, error::Error> {
168 let mut url = reqwest::Url::parse(
169 &format!("{}/accounts", BASE_URL)
170 ).map_err(error::Error::UrlParse)?;
171 options.add_params(&mut url);
172
173 let res = reqwest::Client::new()
174 .get(url)
175 .header("Authorization", self.auth_header())
176 .send()
177 .await
178 .map_err(error::Error::Request)?;
179
180 match res.status() {
181 reqwest::StatusCode::OK => {
182 let body = res.text().await.map_err(error::Error::BodyRead)?;
183 let account_response: ListAccountsResponse =
184 serde_json::from_str(&body).map_err(error::Error::Json)?;
185
186 Ok(account_response)
187 },
188 _ => {
189 let body = res.text().await.map_err(error::Error::BodyRead)?;
190 let error: error::ErrorResponse =
191 serde_json::from_str(&body).map_err(error::Error::Json)?;
192
193 Err(error::Error::Api(error))
194 }
195 }
196 }
197
198 pub async fn get_account(
200 &self,
201 id: &str,
202 ) -> Result<GetAccountResponse, error::Error> {
203 if id.is_empty() {
207 panic!("The provided account ID must not be empty.");
208 }
209
210 let url = reqwest::Url::parse(
211 &format!("{}/accounts/{}", BASE_URL, id)
212 ).map_err(error::Error::UrlParse)?;
213
214 let res = reqwest::Client::new()
215 .get(url)
216 .header("Authorization", self.auth_header())
217 .send()
218 .await
219 .map_err(error::Error::Request)?;
220
221 match res.status() {
222 reqwest::StatusCode::OK => {
223 let body = res.text().await.map_err(error::Error::BodyRead)?;
224 let account_response: GetAccountResponse =
225 serde_json::from_str(&body).map_err(error::Error::Json)?;
226
227 Ok(account_response)
228 },
229 _ => {
230 let body = res.text().await.map_err(error::Error::BodyRead)?;
231 let error: error::ErrorResponse =
232 serde_json::from_str(&body).map_err(error::Error::Json)?;
233
234 Err(error::Error::Api(error))
235 }
236 }
237 }
238}
239
240implement_pagination_v1!(ListAccountsResponse);