1use chrono::{serde::ts_milliseconds, DateTime, Utc};
2use serde::{Deserialize, Deserializer};
3
4#[derive(Deserialize, Debug, PartialEq)]
5pub enum AccessLevel {
6 #[serde(rename = "ANONYMOUS")]
7 Anonymous,
8 #[serde(rename = "CANDIDATE")]
9 Candidate,
10 #[serde(rename = "CLIENT")]
11 Client,
12}
13
14#[derive(Deserialize, Debug, PartialEq)]
15pub struct UserInfo {
16 #[serde(rename = "accessLevel")]
17 pub access_level: AccessLevel,
18 #[serde(default, rename = "userId")]
19 pub user_id: String,
20}
21
22#[derive(Deserialize, Debug, PartialEq)]
23pub struct Session {
24 #[serde(rename = "sessionid")]
25 pub id: String,
26 pub ttl: u32,
27}
28
29#[derive(Deserialize, Debug, PartialEq)]
30pub enum ResultCode {
31 #[serde(rename = "OK")]
32 Ok,
33 #[serde(rename = "WAITING_CONFIRMATION")]
34 WaitingConfirmation,
35}
36
37#[derive(Deserialize, Debug, PartialEq)]
38pub struct Nothing {}
39
40#[derive(Deserialize, Debug, PartialEq)]
41pub struct Account {
42 #[serde(rename = "externalAccountNumber")]
43 pub external_number: String,
44 #[serde(rename = "accountGroup")]
45 pub group: String,
46 #[serde(rename = "moneyAmount")]
47 pub money_amount: MoneyAmount,
48 pub name: String,
49 pub id: String,
50}
51
52#[derive(Deserialize, Debug, PartialEq)]
53pub struct MoneyAmount {
54 pub currency: Currency,
55 pub value: f32,
56}
57
58#[allow(clippy::upper_case_acronyms)]
59#[derive(Debug, PartialEq)]
60pub enum Currency {
61 EUR,
62 RUB,
63 USD,
64 BYN,
65}
66
67impl<'de> Deserialize<'de> for Currency {
68 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
69 where
70 D: Deserializer<'de>,
71 {
72 #[derive(Deserialize)]
73 struct Outer {
74 name: Inner,
75 }
76
77 #[allow(clippy::upper_case_acronyms)]
78 #[derive(Deserialize)]
79 enum Inner {
80 RUB,
81 USD,
82 EUR,
83 BYN,
84 }
85
86 let helper = Outer::deserialize(deserializer)?;
87 Ok(match helper.name {
88 Inner::RUB => Currency::RUB,
89 Inner::USD => Currency::USD,
90 Inner::EUR => Currency::EUR,
91 Inner::BYN => Currency::BYN,
92 })
93 }
94}
95
96#[derive(Deserialize, Debug, PartialEq)]
97pub struct ResponsePayload<T> {
98 #[serde(rename = "resultCode")]
99 pub result_code: ResultCode,
100 pub payload: Option<T>,
102 pub confirmations: Option<Vec<String>>,
104 #[serde(rename = "initialOperation")]
105 pub initial_operation: Option<String>,
106 #[serde(rename = "operationTicket")]
107 pub operation_ticket: Option<String>,
108}
109
110#[derive(Deserialize, Debug, PartialEq)]
111pub enum OperationType {
112 Credit,
113 Debit,
114}
115
116#[derive(Deserialize, Debug, PartialEq)]
117pub enum OperationGroup {
118 #[serde(rename = "PAY")]
119 Pay,
120 #[serde(rename = "INCOME")]
121 Income,
122 #[serde(rename = "TRANSFER")]
123 Transfer,
124 #[serde(rename = "CASH")]
125 Cash,
126 #[serde(rename = "CORRECTION")]
127 Correction,
128 #[serde(rename = "CHARGE")]
129 Charge,
130 #[serde(rename = "INTERNAL")]
131 Internal,
132}
133
134#[derive(Debug, PartialEq)]
135pub struct Operation {
136 pub id: String,
137 pub operation_type: OperationType,
138 pub description: String,
139 pub amount: MoneyAmount,
140 pub account_amount: MoneyAmount,
141 pub operation_time: DateTime<Utc>,
142 pub spending_category: String,
143 pub mcc: u16,
144 pub category: String,
145 pub subcategory: Option<String>,
146 pub account: String,
147 pub merchant: Option<String>,
148 pub group: OperationGroup,
149 pub subgroup: Option<String>,
150}
151
152impl<'de> Deserialize<'de> for Operation {
153 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154 where
155 D: Deserializer<'de>,
156 {
157 #[derive(Deserialize)]
158 struct Outer {
159 id: String,
160 #[serde(rename = "type")]
161 operation_type: OperationType,
162 description: String,
163 amount: MoneyAmount,
164 #[serde(rename = "accountAmount")]
165 account_amount: MoneyAmount,
166 #[serde(rename = "operationTime")]
167 operation_time: InnerTime,
168 #[serde(rename = "spendingCategory")]
169 spending_category: InnerName,
170 mcc: u16,
171 category: InnerName,
172 subcategory: Option<String>,
173 account: String,
174 merchant: Option<InnerName>,
175 group: OperationGroup,
176 subgroup: Option<InnerName>,
177 }
178
179 #[derive(Deserialize)]
180 struct InnerName {
181 name: String,
182 }
183
184 #[derive(Deserialize)]
185 struct InnerTime {
186 #[serde(with = "ts_milliseconds")]
187 milliseconds: DateTime<Utc>,
188 }
189
190 let helper = Outer::deserialize(deserializer)?;
191 Ok(Operation {
192 id: helper.id,
193 operation_type: helper.operation_type,
194 description: helper.description,
195 amount: helper.amount,
196 account_amount: helper.account_amount,
197 operation_time: helper.operation_time.milliseconds,
198 spending_category: helper.spending_category.name,
199 mcc: helper.mcc,
200 category: helper.category.name,
201 subcategory: helper.subcategory,
202 account: helper.account,
203 merchant: match helper.merchant {
204 Some(val) => Some(val.name),
205 None => None,
206 },
207 group: helper.group,
208 subgroup: match helper.subgroup {
209 Some(val) => Some(val.name),
210 None => None,
211 },
212 })
213 }
214}