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}