akahu_client/models/transaction.rs
1//! Rust structs representing the Transaction Model Akahu uses, the documentation
2//! for the Akahu model this is derived from is
3//! [here](https://developers.akahu.nz/docs/the-transaction-model).
4
5use serde::{Deserialize, Serialize};
6
7use crate::{AccountId, BankAccountNumber, CategoryId, ConnectionId, MerchantId, TransactionId};
8
9/// A transaction is a record of money moving between two accounts. Akahu can
10/// provide transaction data from connected accounts for all bank integrations
11/// and a selection of non-bank integrations. See the [Supported
12/// Integrations](https://developers.akahu.nz/docs/integrations) reference for
13/// the full list of integrations that have transaction data available.
14///
15/// In addition to the basic transaction data that Akahu retrieves from the
16/// connected institution (such as date, amount, description), Akahu enriches
17/// transactions with merchant and categorisation data where possible. More
18/// information on enrichment data is provided in detail in this document.
19///
20/// Transaction data is only available to apps with the TRANSACTIONS scope. In
21/// addition, further permissions are required to access enriched transaction
22/// data. Personal apps have full access to enriched transactions by default. If
23/// you have a full Akahu app and would like access to transaction data, get in
24/// touch via [hello@akahu.nz](mailto:hello@akahu.nz) or our [Slack
25/// workspace](http://slack.akahu.io/).
26///
27/// See our [Accessing Transactional
28/// Data](https://developers.akahu.nz/docs/accessing-transactional-data/) guide
29/// to learn how to retrieve transactions from Akahu's API.
30#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
31pub struct Transaction {
32 /// The `id` key is a unique identifier for the transaction in the Akahu
33 /// system. It is always be prefixed by trans_ so that you can tell that it
34 /// refers to a transaction.
35 #[serde(rename = "_id")]
36 pub id: TransactionId,
37
38 /// The `account` key indicates which account this transaction belongs to.
39 /// See our guide to Accessing Account Data to learn how to get this
40 /// account, and our Account Model docs to learn more about accounts.
41 #[serde(rename = "_account")]
42 pub account: AccountId,
43
44 /// This is the ID of provider that Akahu has retrieved this transaction
45 /// from. You can get a list of connections from our
46 /// [/connections](https://developers.akahu.nz/reference/get_connections)
47 /// endpoint.
48 #[serde(rename = "_connection")]
49 pub connection: ConnectionId,
50
51 /// The time that Akahu first saw this transaction (as an ISO 8601
52 /// timestamp). This is unrelated to the transaction date (when the
53 /// transaction occurred) because Akahu may have retrieved an old
54 /// transaction.
55 pub created_at: chrono::DateTime<chrono::Utc>,
56
57 /// The date that the transaction was posted with the account holder, as an
58 /// ISO 8601 timestamp. In many cases this will only be accurate to the day,
59 /// due to the level of detail provided by the bank.
60 pub date: chrono::DateTime<chrono::Utc>,
61
62 /// The transacton description as provided by the bank. Some minor cleanup
63 /// is done by Akahu (such as whitespace normalisation), but this value is
64 /// otherwise direct from the bank.
65 pub description: String,
66
67 /// The amount of money that was moved by this transaction.
68 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
69 pub amount: rust_decimal::Decimal,
70
71 /// If available, the account balance immediately after this transaction was
72 /// made. This value is direct from the bank and not modified by Akahu.
73 #[serde(
74 default,
75 skip_serializing_if = "Option::is_none",
76 with = "rust_decimal::serde::arbitrary_precision_option"
77 )]
78 pub balance: Option<rust_decimal::Decimal>,
79
80 /// What sort of transaction this is. Akahu tries to find a specific transaction
81 /// type, falling back to "CREDIT" or "DEBIT" if nothing else is available.
82 ///
83 /// [<https://developers.akahu.nz/docs/the-transaction-model#type>]
84 #[serde(rename = "type")]
85 pub kind: TransactionKind,
86
87 /// This is data added by the Akahu enrichment engine. You must have
88 /// additional permissions to view this data.
89 ///
90 /// [<https://developers.akahu.nz/docs/the-transaction-model#enriched-transaction-data>]
91 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
92 pub enriched_data: Option<EnrichedTransactionData>,
93}
94
95/// What sort of transaction this is. Akahu tries to find a specific transaction
96/// type, falling back to "CREDIT" or "DEBIT" if nothing else is available.
97///
98/// [<https://developers.akahu.nz/docs/the-transaction-model#type>]
99#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
100pub enum TransactionKind {
101 /// Money has entered the account.
102 #[serde(rename = "CREDIT")]
103 Credit,
104 /// Money has left the account.
105 #[serde(rename = "DEBIT")]
106 Debit,
107 /// A payment to an external account.
108 #[serde(rename = "PAYMENT")]
109 Payment,
110 /// A transfer between accounts that are associated with the same credentials.
111 #[serde(rename = "TRANSFER")]
112 Transfer,
113 /// An automatic payment.
114 #[serde(rename = "STANDING ORDER")]
115 StandingOrder,
116 /// A payment made via the EFTPOS system.
117 #[serde(rename = "EFTPOS")]
118 Eftpos,
119 /// An interest payment from the account provider.
120 #[serde(rename = "INTEREST")]
121 Interest,
122 /// A fee from the account provider.
123 #[serde(rename = "FEE")]
124 Fee,
125 /// A tax payment.
126 #[serde(rename = "TAX")]
127 Tax,
128 /// A credit card payment.
129 #[serde(rename = "CREDIT CARD")]
130 CreditCard,
131 /// A direct debit payment.
132 #[serde(rename = "DIRECT DEBIT")]
133 DirectDebit,
134 /// A direct credit (someone paying into the account).
135 #[serde(rename = "DIRECT CREDIT")]
136 DirectCredit,
137 /// An ATM deposit or withdrawal.
138 #[serde(rename = "ATM")]
139 Atm,
140 /// A payment related to a loan.
141 #[serde(rename = "LOAN")]
142 Loan,
143}
144
145/// This is data added by the Akahu enrichment engine. You must have additional
146/// permissions to view this data.
147///
148/// [<https://developers.akahu.nz/docs/the-transaction-model#enriched-transaction-data>]
149#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
150pub struct EnrichedTransactionData {
151 /// Category information for this transaction
152 pub category: TransactionCategory,
153 /// Merchant information for this transaction
154 pub merchant: TransactionMerchant,
155}
156
157/// Transaction category information from Akahu enrichment.
158///
159/// Categories are based on the New Zealand Financial Category Codes (NZFCC) standard.
160#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
161pub struct TransactionCategory {
162 /// Unique category identifier
163 #[serde(rename = "_id")]
164 pub id: CategoryId,
165 /// NZFCC category code
166 pub name: nzfcc::NzfccCode,
167 /// Category groupings
168 pub groups: TransactionGroups,
169}
170
171/// Category groupings for different classification systems.
172#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
173pub struct TransactionGroups {
174 /// Personal finance category group
175 pub personal_finance: PersonalFinanceGroup,
176 /// Other category groupings (future extension)
177 #[serde(flatten)]
178 pub other_groups: Option<std::collections::HashMap<String, serde_json::Value>>,
179}
180
181/// Personal finance category group.
182#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
183pub struct PersonalFinanceGroup {
184 /// Category group identifier
185 #[serde(rename = "_id")]
186 pub id: CategoryId,
187 /// Category group name
188 pub name: nzfcc::CategoryGroup,
189}
190
191/// Akahu defines a merchant as the business who was party to this transaction.
192/// For example, "The Warehouse" is a merchant.
193///
194/// Merchant data is provided as a name, an optional website, and a merchant
195///
196/// [<https://developers.akahu.nz/docs/the-transaction-model#merchant>]
197#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
198pub struct TransactionMerchant {
199 /// A unique identifier for the merchant in the Akahu system.
200 ///
201 /// Will always be prefixed with `_merchant`.
202 #[serde(rename = "_id")]
203 pub id: MerchantId,
204 /// The name of the merchant, for example "The Warehouse".
205 pub name: String,
206 /// The merchant's website, if available.
207 #[serde(default, skip_serializing_if = "Option::is_none")]
208 pub website: Option<url::Url>,
209}
210
211/// This is other metadata that we extract from the transaction, including the
212/// following fields (where possible).
213///
214/// [<https://developers.akahu.nz/docs/the-transaction-model#meta>]
215#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
216pub struct TransactionMeta {
217 /// Fields that are entered when a payment is made.
218 #[serde(default, skip_serializing_if = "Option::is_none")]
219 pub particulars: Option<String>,
220
221 /// Fields that are entered when a payment is made.
222 #[serde(default, skip_serializing_if = "Option::is_none")]
223 pub code: Option<String>,
224
225 /// Fields that are entered when a payment is made.
226 #[serde(default, skip_serializing_if = "Option::is_none")]
227 pub reference: Option<String>,
228
229 /// The formatted NZ bank account number of the other party to this transaction.
230 #[serde(default, skip_serializing_if = "Option::is_none")]
231 pub other_account: Option<BankAccountNumber>,
232
233 /// If this transaction was made in another currency, details about the currency conversion.
234 #[serde(default, skip_serializing_if = "Option::is_none")]
235 pub conversion: Option<TransactionConversion>,
236
237 /// If this transaction was made with a credit or debit card, we may be able to extract the
238 /// card number used to make the transaction.
239 #[serde(default, skip_serializing_if = "Option::is_none")]
240 pub card_suffix: Option<String>,
241
242 /// URL of a .png image for this transaction. This is typically the logo of the transaction merchant.
243 /// If no logo is available, a placeholder image is provided.
244 #[serde(default, skip_serializing_if = "Option::is_none")]
245 pub logo: Option<url::Url>,
246}
247
248/// Details about a currency conversion for a transaction made in another currency.
249#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
250pub struct TransactionConversion {
251 /// The amount in the foreign currency.
252 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
253 pub amount: rust_decimal::Decimal,
254 /// The currency code of the foreign currency (e.g. "GBP").
255 pub currency: iso_currency::Currency,
256 /// The conversion rate applied.
257 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
258 pub rate: rust_decimal::Decimal,
259}
260
261/// A pending transaction that has not yet been settled.
262///
263/// Pending transactions are not stable - the date or description may change due to
264/// the unreliable nature of underlying NZ bank data. They are not assigned unique
265/// identifiers and are not enriched by Akahu.
266///
267/// [<https://developers.akahu.nz/docs/accessing-transactional-data#pending-transactions>]
268#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
269pub struct PendingTransaction {
270 /// The account this pending transaction belongs to.
271 #[serde(rename = "_account")]
272 pub account: AccountId,
273
274 /// This is the ID of provider that Akahu has retrieved this transaction from.
275 #[serde(rename = "_connection")]
276 pub connection: ConnectionId,
277
278 /// The time that this pending transaction was last updated (as an ISO 8601 timestamp).
279 pub updated_at: chrono::DateTime<chrono::Utc>,
280
281 /// The date that the transaction was posted with the account holder, as an
282 /// ISO 8601 timestamp. May change before the transaction settles.
283 pub date: chrono::DateTime<chrono::Utc>,
284
285 /// The transaction description as provided by the bank. May change before settlement.
286 pub description: String,
287
288 /// The amount of money that will be moved by this transaction.
289 #[serde(with = "rust_decimal::serde::arbitrary_precision")]
290 pub amount: rust_decimal::Decimal,
291
292 /// What sort of transaction this is.
293 #[serde(rename = "type")]
294 pub kind: TransactionKind,
295
296 /// Additional metadata about the transaction.
297 #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
298 pub meta: Option<TransactionMeta>,
299}