summaryrefslogtreecommitdiff
path: root/importers/actualbudget/src
diff options
context:
space:
mode:
Diffstat (limited to 'importers/actualbudget/src')
-rw-r--r--importers/actualbudget/src/getters.rs61
-rw-r--r--importers/actualbudget/src/inserters.rs120
-rw-r--r--importers/actualbudget/src/main.rs57
-rw-r--r--importers/actualbudget/src/models/actualbudget/account.rs15
-rw-r--r--importers/actualbudget/src/models/actualbudget/category.rs15
-rw-r--r--importers/actualbudget/src/models/actualbudget/date.rs69
-rw-r--r--importers/actualbudget/src/models/actualbudget/mod.rs5
-rw-r--r--importers/actualbudget/src/models/actualbudget/transaction.rs43
-rw-r--r--importers/actualbudget/src/models/actualbudget/zero_budget.rs30
-rw-r--r--importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs57
-rw-r--r--importers/actualbudget/src/models/budgeting_app/account.rs8
-rw-r--r--importers/actualbudget/src/models/budgeting_app/budget_update.rs10
-rw-r--r--importers/actualbudget/src/models/budgeting_app/category.rs4
-rw-r--r--importers/actualbudget/src/models/budgeting_app/category_transfer.rs7
-rw-r--r--importers/actualbudget/src/models/budgeting_app/date_time_utc.rs20
-rw-r--r--importers/actualbudget/src/models/budgeting_app/mod.rs7
-rw-r--r--importers/actualbudget/src/models/budgeting_app/transaction.rs11
-rw-r--r--importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs7
-rw-r--r--importers/actualbudget/src/models/mod.rs2
-rw-r--r--importers/actualbudget/src/transformers.rs221
20 files changed, 0 insertions, 769 deletions
diff --git a/importers/actualbudget/src/getters.rs b/importers/actualbudget/src/getters.rs
deleted file mode 100644
index 88a660d..0000000
--- a/importers/actualbudget/src/getters.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::models::actualbudget::{
- account::Account, category::Category, date::Date, transaction::Transaction,
- zero_budget::ZeroBudget,
-};
-use sqlite::Connection;
-
-pub fn get_first_transaction_date(connection: &Connection) -> Date {
- let mut statement = connection
- .prepare("select min(date) as min_date from transactions;")
- .unwrap();
- match statement.next() {
- Ok(sqlite::State::Row) => Date::from_date_row(&statement, "min_date"),
- err => panic!("Could not find first transaction date: {:?}", err),
- }
-}
-
-pub fn get_accounts(connection: &Connection) -> Vec<Account> {
- let mut statement = connection.prepare("select * from accounts;").unwrap();
- let mut accounts = Vec::<Account>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- accounts.push(Account::from_row(&statement));
- }
- accounts
-}
-
-pub fn get_categories(connection: &Connection) -> Vec<Category> {
- let mut statement = connection.prepare("select * from categories;").unwrap();
- let mut categories = Vec::<Category>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- categories.push(Category::from_row(&statement));
- }
- categories
-}
-
-pub fn get_zero_budgets(connection: &Connection) -> Vec<ZeroBudget> {
- let mut statement = connection.prepare("select * from zero_budgets;").unwrap();
- let mut zero_budgets = Vec::<ZeroBudget>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- zero_budgets.push(ZeroBudget::from_row(&statement));
- }
- zero_budgets
-}
-
-pub fn get_category_transfers_account(connection: &Connection) -> Account {
- let mut statement = connection
- .prepare("select * from accounts where name = 'Category transfers';")
- .unwrap();
- match statement.next() {
- Ok(sqlite::State::Row) => Account::from_row(&statement),
- _ => panic!("Could not determine category transfers account"),
- }
-}
-
-pub fn get_transactions(connection: &Connection) -> Vec<Transaction> {
- let mut statement = connection.prepare("select * from transactions;").unwrap();
- let mut transactions = Vec::<Transaction>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- transactions.push(Transaction::from_row(&statement));
- }
- transactions
-}
diff --git a/importers/actualbudget/src/inserters.rs b/importers/actualbudget/src/inserters.rs
deleted file mode 100644
index 179de97..0000000
--- a/importers/actualbudget/src/inserters.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::models::budgeting_app::{
- account::Account, budget_update::BudgetUpdate, category::Category,
- category_transfer::CategoryTransfer, transaction::Transaction,
- transaction_categorisation::TransactionCategorisation,
-};
-use sqlite::Connection;
-
-pub fn insert_accounts(connection: &Connection, accounts: &[Account]) {
- for account in accounts {
- let str = format!(
- "
- insert into
- accounts(id, name, opening_balance, opening_date)
- values({0}, '{1}', {2}, '{3}');
- ",
- account.id,
- escape_str(&account.name),
- account.opening_balance,
- account.opening_date
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_categories(connection: &Connection, categories: &[Category]) {
- for category in categories {
- let str = format!(
- "
- insert into
- categories(id, name)
- values({0}, '{1}');
- ",
- category.id,
- escape_str(&category.name),
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_budget_updates(connection: &Connection, budget_updates: &[BudgetUpdate]) {
- for budget_update in budget_updates {
- let str = format!(
- "
- insert into
- budget_updates(id, category_id, date, new_budget, new_period)
- values({0}, {1}, '{2}', {3}, {4});
- ",
- budget_update.id,
- budget_update.category_id,
- budget_update.date,
- budget_update.new_budget,
- budget_update.new_period,
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_transactions(connection: &Connection, transactions: &[Transaction]) {
- for transaction in transactions {
- let str = format!(
- "
- insert into
- transactions(id, description, payee, quantity, date, account_id)
- values({0}, '{1}', '{2}', {3}, '{4}', {5});
- ",
- transaction.id,
- escape_str(&transaction.description),
- escape_str(&transaction.payee),
- transaction.quantity,
- transaction.date,
- transaction.account_id,
- );
- connection
- .execute(str.clone())
- .unwrap_or_else(|_| panic!("{}", &str.clone()));
- }
-}
-
-pub fn insert_transaction_categorisations(
- connection: &Connection,
- transaction_categorisations: &[TransactionCategorisation],
-) {
- for transaction_categorisation in transaction_categorisations {
- let str = format!(
- "
- insert into
- transaction_categorisations(id, description, quantity, transaction_id, category_id)
- values({0}, '{1}', {2}, {3}, {4});
- ",
- transaction_categorisation.id,
- escape_str(&transaction_categorisation.description),
- transaction_categorisation.quantity,
- transaction_categorisation.transaction_id,
- transaction_categorisation.category_id,
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_category_transfers(connection: &Connection, category_transfers: &[CategoryTransfer]) {
- for category_transfer in category_transfers {
- let str = format!(
- "
- insert into
- category_transfers(id, description, quantity, from_category_id, to_category_id)
- values({0}, '{1}', {2}, {3}, {4});
- ",
- category_transfer.id,
- escape_str(&category_transfer.description),
- category_transfer.quantity,
- category_transfer.from_category_id,
- category_transfer.to_category_id,
- );
- connection.execute(str).unwrap();
- }
-}
-
-fn escape_str(str: &str) -> String {
- str.replace("'", "''")
-}
diff --git a/importers/actualbudget/src/main.rs b/importers/actualbudget/src/main.rs
deleted file mode 100644
index 495216e..0000000
--- a/importers/actualbudget/src/main.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-pub mod getters;
-pub mod inserters;
-pub mod models;
-pub mod transformers;
-
-use getters::*;
-use inserters::*;
-use sqlite::Connection;
-
-fn main() {
- let connection_src = sqlite::open("in.sqlite").unwrap();
- let connection_dest = sqlite::open("out.sqlite").unwrap();
-
- let actualbudget_first_transaction_date = get_first_transaction_date(&connection_src);
- let actualbudget_accounts = get_accounts(&connection_src);
- let actualbudget_categories = get_categories(&connection_src);
- let actualbudget_zero_budgets = get_zero_budgets(&connection_src);
- let actualbudget_category_transfers_account = get_category_transfers_account(&connection_src);
- let actualbudget_transactions = get_transactions(&connection_src);
-
- let first_transaction_date = transformers::transform_date(&actualbudget_first_transaction_date);
- let accounts =
- transformers::transform_accounts(&actualbudget_accounts, &first_transaction_date);
- let categories = transformers::transform_categories(&actualbudget_categories);
- let budget_updates = transformers::transform_budget_updates(&actualbudget_zero_budgets);
- let (transactions, transaction_categorisations) = transformers::transform_transactions(
- &actualbudget_transactions,
- &actualbudget_category_transfers_account,
- );
- let category_transfers = transformers::transform_category_transfers(
- &actualbudget_transactions,
- &actualbudget_category_transfers_account,
- );
-
- clear_destination(&connection_dest);
- insert_accounts(&connection_dest, &accounts);
- insert_categories(&connection_dest, &categories);
- insert_budget_updates(&connection_dest, &budget_updates);
- insert_transactions(&connection_dest, &transactions);
- insert_transaction_categorisations(&connection_dest, &transaction_categorisations);
- insert_category_transfers(&connection_dest, &category_transfers);
-}
-
-fn clear_destination(connection: &Connection) {
- connection
- .execute(
- "
- delete from accounts;
- delete from budget_updates;
- delete from categories;
- delete from transaction_categorisations;
- delete from category_transfers;
- delete from transactions;
- ",
- )
- .unwrap();
-}
diff --git a/importers/actualbudget/src/models/actualbudget/account.rs b/importers/actualbudget/src/models/actualbudget/account.rs
deleted file mode 100644
index 727c082..0000000
--- a/importers/actualbudget/src/models/actualbudget/account.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use sqlite::Statement;
-
-pub struct Account {
- pub id: String,
- pub name: String,
-}
-
-impl Account {
- pub fn from_row(statement: &Statement) -> Account {
- Account {
- id: statement.read("id").unwrap(),
- name: statement.read("name").unwrap(),
- }
- }
-}
diff --git a/importers/actualbudget/src/models/actualbudget/category.rs b/importers/actualbudget/src/models/actualbudget/category.rs
deleted file mode 100644
index 21fdf80..0000000
--- a/importers/actualbudget/src/models/actualbudget/category.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use sqlite::Statement;
-
-pub struct Category {
- pub id: String,
- pub name: String,
-}
-
-impl Category {
- pub fn from_row(statement: &Statement) -> Category {
- Category {
- id: statement.read("id").unwrap(),
- name: statement.read("name").unwrap(),
- }
- }
-}
diff --git a/importers/actualbudget/src/models/actualbudget/date.rs b/importers/actualbudget/src/models/actualbudget/date.rs
deleted file mode 100644
index bd37c46..0000000
--- a/importers/actualbudget/src/models/actualbudget/date.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use sqlite::Statement;
-
-#[derive(Clone, PartialEq, Eq)]
-pub struct Date {
- value: i64,
- last_date_part: DatePart,
-}
-
-#[derive(Clone, PartialOrd, PartialEq, Eq)]
-enum DatePart {
- MonthOfYear,
- DayOfMonth,
-}
-
-// actualbudget represents dates as numbers which "look like" the corresponding
-// ISO string when written in decimal. E.g. 20240901 represents 1 Sep 2024. It
-// also uses month specifiers, e.g. 202409 to represent Sep 2024. In this case,
-// we interpret this as the first day of the month, e.g. 2024-09-01.
-
-impl Date {
- pub fn from_date_row(statement: &Statement, column: &str) -> Date {
- Date {
- value: statement.read::<i64, _>(column).unwrap(),
- last_date_part: DatePart::DayOfMonth,
- }
- }
-
- pub fn from_month_row(statement: &Statement, column: &str) -> Date {
- Date {
- value: statement.read::<i64, _>(column).unwrap() * 100 + 1,
- last_date_part: DatePart::MonthOfYear,
- }
- }
-
- pub fn to_iso(&self) -> String {
- format!("{0}-{1}-{2}", self.year(), self.month(), self.day())
- }
-
- pub fn year(&self) -> String {
- self.value.to_string()[0..4].to_string()
- }
-
- pub fn month(&self) -> String {
- self.value.to_string()[4..6].to_string()
- }
-
- pub fn day(&self) -> String {
- self.dayified_value().to_string()[6..8].to_string()
- }
-
- fn dayified_value(&self) -> i64 {
- match self.last_date_part {
- DatePart::DayOfMonth => self.value,
- DatePart::MonthOfYear => self.value * 100 + 1,
- }
- }
-}
-
-impl Ord for Date {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- self.dayified_value().cmp(&other.dayified_value())
- }
-}
-
-impl PartialOrd for Date {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
diff --git a/importers/actualbudget/src/models/actualbudget/mod.rs b/importers/actualbudget/src/models/actualbudget/mod.rs
deleted file mode 100644
index 5ca472f..0000000
--- a/importers/actualbudget/src/models/actualbudget/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub mod account;
-pub mod category;
-pub mod date;
-pub mod transaction;
-pub mod zero_budget;
diff --git a/importers/actualbudget/src/models/actualbudget/transaction.rs b/importers/actualbudget/src/models/actualbudget/transaction.rs
deleted file mode 100644
index 0a21cfe..0000000
--- a/importers/actualbudget/src/models/actualbudget/transaction.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use sqlite::Statement;
-
-use super::date::Date;
-
-#[derive(Clone)]
-pub struct Transaction {
- pub id: String,
- pub is_parent: bool,
- pub is_child: bool,
- pub account_id: String,
- pub category_id: String,
- pub amount: i64,
- pub payee: String,
- pub notes: String,
- pub date: Date,
- pub parent_id: Option<String>,
-}
-
-impl Transaction {
- pub fn from_row(statement: &Statement) -> Transaction {
- Transaction {
- id: statement.read("id").unwrap(),
- is_parent: statement.read::<i64, &str>("isParent").unwrap() == 1,
- is_child: statement.read::<i64, &str>("isChild").unwrap() == 1,
- account_id: statement.read("acct").unwrap(),
- category_id: statement
- .read::<Option<String>, &str>("category")
- .map(Option::<String>::unwrap_or_default)
- .unwrap(),
- amount: statement.read("amount").unwrap(),
- payee: statement
- .read::<Option<String>, &str>("description")
- .map(Option::<String>::unwrap_or_default)
- .unwrap(),
- notes: statement
- .read::<Option<String>, &str>("notes")
- .map(Option::<String>::unwrap_or_default)
- .unwrap(),
- date: Date::from_date_row(statement, "date"),
- parent_id: statement.read("parent_id").unwrap(),
- }
- }
-}
diff --git a/importers/actualbudget/src/models/actualbudget/zero_budget.rs b/importers/actualbudget/src/models/actualbudget/zero_budget.rs
deleted file mode 100644
index 87c88e7..0000000
--- a/importers/actualbudget/src/models/actualbudget/zero_budget.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use sqlite::Statement;
-
-use super::date::Date;
-
-#[derive(Clone)]
-pub struct ZeroBudget {
- pub id: String,
- pub month: Date,
- pub category_id: String,
- pub amount: i64,
- pub do_carry_over: bool,
-}
-
-impl ZeroBudget {
- pub fn from_row(statement: &Statement) -> ZeroBudget {
- ZeroBudget {
- id: statement.read("id").unwrap(),
- month: Date::from_month_row(statement, "month"),
- category_id: statement.read("category").unwrap(),
- amount: statement.read("amount").unwrap(),
- do_carry_over: match statement.read::<i64, &str>("carryover").unwrap() {
- 0 => false,
- 1 => true,
- carryover => {
- panic!("carryover column was neither 0 nor 1, but instead {carryover}")
- }
- },
- }
- }
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs b/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs
deleted file mode 100644
index e44fa8c..0000000
--- a/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use chrono::{DateTime, Datelike, Utc};
-use diesel::{
- deserialize::{FromSql, FromSqlRow},
- expression::AsExpression,
- serialize::ToSql,
- sql_types::Text,
- sqlite::Sqlite,
-};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Eq,
- PartialEq,
- Ord,
- PartialOrd,
- Serialize,
- Deserialize,
- Copy,
- Clone,
- Debug,
- AsExpression,
- FromSqlRow,
-)]
-#[diesel(sql_type=Text)]
-pub struct DateTimeUtc(DateTime<Utc>);
-
-impl DateTimeUtc {
- pub fn day_diff(&self, other: &DateTimeUtc) -> u32 {
- self.0
- .num_days_from_ce()
- .abs_diff(other.0.num_days_from_ce())
- }
-
- pub fn new(date_time_utc: DateTime<Utc>) -> Self {
- Self(date_time_utc)
- }
-}
-
-impl ToSql<Text, Sqlite> for DateTimeUtc {
- fn to_sql<'b>(
- &'b self,
- out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
- ) -> diesel::serialize::Result {
- out.set_value((*self).0.to_rfc3339());
- Ok(diesel::serialize::IsNull::No)
- }
-}
-
-impl FromSql<Text, Sqlite> for DateTimeUtc {
- fn from_sql(
- bytes: <Sqlite as diesel::backend::Backend>::RawValue<'_>,
- ) -> diesel::deserialize::Result<Self> {
- let str: String = FromSql::<Text, Sqlite>::from_sql(bytes)?;
- let date_time = str.as_str().parse::<DateTime<Utc>>()?;
- Ok(DateTimeUtc(date_time))
- }
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/account.rs b/importers/actualbudget/src/models/budgeting_app/account.rs
deleted file mode 100644
index 165b55c..0000000
--- a/importers/actualbudget/src/models/budgeting_app/account.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-use super::date_time_utc::DateTimeUtc;
-
-pub struct Account {
- pub id: i32,
- pub name: String,
- pub opening_balance: i32,
- pub opening_date: DateTimeUtc,
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/budget_update.rs b/importers/actualbudget/src/models/budgeting_app/budget_update.rs
deleted file mode 100644
index 9958446..0000000
--- a/importers/actualbudget/src/models/budgeting_app/budget_update.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use super::date_time_utc::DateTimeUtc;
-
-#[derive(Clone)]
-pub struct BudgetUpdate {
- pub id: i32,
- pub category_id: i32,
- pub date: DateTimeUtc,
- pub new_budget: i32,
- pub new_period: i32,
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/category.rs b/importers/actualbudget/src/models/budgeting_app/category.rs
deleted file mode 100644
index 3f51dfd..0000000
--- a/importers/actualbudget/src/models/budgeting_app/category.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-pub struct Category {
- pub id: i32,
- pub name: String,
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/category_transfer.rs b/importers/actualbudget/src/models/budgeting_app/category_transfer.rs
deleted file mode 100644
index 0097429..0000000
--- a/importers/actualbudget/src/models/budgeting_app/category_transfer.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub struct CategoryTransfer {
- pub id: i32,
- pub description: String,
- pub quantity: i32,
- pub from_category_id: i32,
- pub to_category_id: i32,
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs b/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs
deleted file mode 100644
index 69cdfe2..0000000
--- a/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::{fmt::Display, str::FromStr};
-
-use chrono::{DateTime, Utc};
-
-#[derive(Clone)]
-pub struct DateTimeUtc(DateTime<Utc>);
-
-impl DateTimeUtc {
- pub fn new(date: &str) -> Self {
- let mut date_time = String::from(date);
- date_time.push_str("T00:00:00.000Z");
- Self(DateTime::<Utc>::from_str(&date_time).unwrap())
- }
-}
-
-impl Display for DateTimeUtc {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.0.fmt(f)
- }
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/mod.rs b/importers/actualbudget/src/models/budgeting_app/mod.rs
deleted file mode 100644
index bca0f99..0000000
--- a/importers/actualbudget/src/models/budgeting_app/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub mod account;
-pub mod budget_update;
-pub mod category;
-pub mod category_transfer;
-pub mod date_time_utc;
-pub mod transaction;
-pub mod transaction_categorisation;
diff --git a/importers/actualbudget/src/models/budgeting_app/transaction.rs b/importers/actualbudget/src/models/budgeting_app/transaction.rs
deleted file mode 100644
index e679e1e..0000000
--- a/importers/actualbudget/src/models/budgeting_app/transaction.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use super::date_time_utc::DateTimeUtc;
-
-#[derive(Clone)]
-pub struct Transaction {
- pub id: i32,
- pub description: String,
- pub payee: String,
- pub quantity: i32,
- pub date: DateTimeUtc,
- pub account_id: i32,
-}
diff --git a/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs b/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs
deleted file mode 100644
index ca7e7f5..0000000
--- a/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub struct TransactionCategorisation {
- pub id: i32,
- pub description: String,
- pub quantity: i32,
- pub transaction_id: i32,
- pub category_id: i32,
-}
diff --git a/importers/actualbudget/src/models/mod.rs b/importers/actualbudget/src/models/mod.rs
deleted file mode 100644
index cf1b71a..0000000
--- a/importers/actualbudget/src/models/mod.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-pub mod actualbudget;
-pub mod budgeting_app;
diff --git a/importers/actualbudget/src/transformers.rs b/importers/actualbudget/src/transformers.rs
deleted file mode 100644
index 678ea05..0000000
--- a/importers/actualbudget/src/transformers.rs
+++ /dev/null
@@ -1,221 +0,0 @@
-use core::panic;
-use std::hash::{DefaultHasher, Hash, Hasher};
-
-use crate::models::{
- actualbudget,
- budgeting_app::{
- account::Account, budget_update::BudgetUpdate, category::Category,
- category_transfer::CategoryTransfer, date_time_utc::DateTimeUtc, transaction::Transaction,
- transaction_categorisation::TransactionCategorisation,
- },
-};
-
-pub fn transform_date(actualbudget_date: &actualbudget::date::Date) -> DateTimeUtc {
- DateTimeUtc::new(&actualbudget_date.to_iso())
-}
-
-pub fn transform_accounts(
- actualbudget_accounts: &[actualbudget::account::Account],
- first_transaction_date: &DateTimeUtc,
-) -> Vec<Account> {
- let mut accounts = Vec::<Account>::new();
- for account in actualbudget_accounts {
- accounts.push(transform_account(account, first_transaction_date));
- }
- accounts
-}
-
-fn transform_account(
- actualbudget_account: &actualbudget::account::Account,
- opening_date: &DateTimeUtc,
-) -> Account {
- Account {
- id: transform_id(&actualbudget_account.id.clone()),
- name: actualbudget_account.name.clone(),
- opening_balance: 0,
- opening_date: opening_date.clone(),
- }
-}
-
-pub fn transform_categories(
- actualbudget_categories: &[actualbudget::category::Category],
-) -> Vec<Category> {
- let mut categories = Vec::<Category>::new();
- for actualbudget_category in actualbudget_categories {
- categories.push(Category {
- id: transform_id(&actualbudget_category.id.clone()),
- name: actualbudget_category.name.clone(),
- })
- }
- categories
-}
-
-fn transform_id(actualbudget_id: &str) -> i32 {
- let mut hasher = DefaultHasher::new();
- actualbudget_id.hash(&mut hasher);
- (hasher.finish() % std::convert::TryInto::<u64>::try_into(i32::MAX).unwrap())
- .try_into()
- .unwrap()
-}
-
-pub fn transform_budget_updates(
- actualbudget_zero_budgets: &[actualbudget::zero_budget::ZeroBudget],
-) -> Vec<BudgetUpdate> {
- let mut budget_updates = Vec::<BudgetUpdate>::new();
- for zero_budget in actualbudget_zero_budgets {
- let first_zero_budget_in_category = get_first_zero_budget_in_category(
- actualbudget_zero_budgets,
- &zero_budget.category_id.clone(),
- );
- if first_zero_budget_in_category.is_some_and(|zb| zb.id == zero_budget.id) {
- continue;
- }
- budget_updates.push(BudgetUpdate {
- id: transform_id(&zero_budget.id.clone()),
- category_id: transform_id(&zero_budget.category_id.clone()),
- date: transform_date(&zero_budget.month.clone()),
- new_budget: zero_budget.amount.try_into().unwrap(),
- new_period: 30,
- })
- }
- budget_updates
-}
-
-fn get_first_zero_budget_in_category(
- actualbudget_zero_budgets: &[actualbudget::zero_budget::ZeroBudget],
- actualbudget_category_id: &str,
-) -> Option<actualbudget::zero_budget::ZeroBudget> {
- let mut category_zero_budgets = actualbudget_zero_budgets.to_vec();
- category_zero_budgets.retain(|zb| zb.category_id == actualbudget_category_id);
- category_zero_budgets
- .iter()
- .min_by_key(|zb| zb.month.clone())
- .cloned()
-}
-
-pub fn transform_transactions(
- actualbudget_transactions: &[actualbudget::transaction::Transaction],
- actualbudget_category_transfers_account: &actualbudget::account::Account,
-) -> (Vec<Transaction>, Vec<TransactionCategorisation>) {
- let mut transactions = Vec::<Transaction>::new();
- let mut transaction_categorisations = Vec::<TransactionCategorisation>::new();
-
- let mut actualbudget_transactions = actualbudget_transactions.to_vec();
- actualbudget_transactions
- .retain(|t| t.category_id.clone() != actualbudget_category_transfers_account.id.clone());
- let mut parent_actualbudget_transactions = actualbudget_transactions.to_vec();
- parent_actualbudget_transactions.retain(|t| t.is_parent);
- let mut child_actualbudget_transactions = actualbudget_transactions.to_vec();
- child_actualbudget_transactions.retain(|t| t.is_child);
- let mut atomic_actualbudget_transactions = actualbudget_transactions.to_vec();
- atomic_actualbudget_transactions.retain(|t| !t.is_parent && !t.is_child);
-
- for atomic_actualbudget_transaction in atomic_actualbudget_transactions {
- let transaction_id = transform_id(&atomic_actualbudget_transaction.id);
-
- transactions.push(Transaction {
- id: transaction_id,
- description: atomic_actualbudget_transaction.notes,
- payee: atomic_actualbudget_transaction.payee,
- quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
- date: transform_date(&atomic_actualbudget_transaction.date),
- account_id: transform_id(&atomic_actualbudget_transaction.account_id),
- });
-
- transaction_categorisations.push(TransactionCategorisation {
- id: transaction_id,
- description: String::new(),
- quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
- transaction_id,
- category_id: transform_id(&atomic_actualbudget_transaction.category_id),
- });
- }
-
- for parent_actualbudget_transaction in parent_actualbudget_transactions {
- let mut child_actualbudget_transactions = child_actualbudget_transactions.to_vec();
- child_actualbudget_transactions.retain(|t| {
- t.parent_id
- .clone()
- .is_some_and(|parent_id| parent_id == parent_actualbudget_transaction.id.clone())
- });
-
- let transaction_id = transform_id(&parent_actualbudget_transaction.id);
-
- transactions.push(Transaction {
- id: transaction_id,
- description: parent_actualbudget_transaction.notes,
- payee: parent_actualbudget_transaction.payee,
- quantity: parent_actualbudget_transaction.amount.try_into().unwrap(),
- date: transform_date(&parent_actualbudget_transaction.date),
- account_id: transform_id(&parent_actualbudget_transaction.account_id),
- });
-
- for child_actualbudget_transaction in child_actualbudget_transactions {
- transaction_categorisations.push(TransactionCategorisation {
- id: transform_id(&child_actualbudget_transaction.id),
- description: child_actualbudget_transaction.notes,
- quantity: child_actualbudget_transaction.amount.try_into().unwrap(),
- transaction_id,
- category_id: transform_id(&child_actualbudget_transaction.category_id),
- });
- }
- }
-
- (transactions, transaction_categorisations)
-}
-
-pub fn transform_category_transfers(
- actualbudget_transactions: &[actualbudget::transaction::Transaction],
- actualbudget_category_transfers_account: &actualbudget::account::Account,
-) -> Vec<CategoryTransfer> {
- let mut category_transfers = Vec::<CategoryTransfer>::new();
-
- let mut actualbudget_category_transfers = actualbudget_transactions.to_vec();
- actualbudget_category_transfers
- .retain(|t| t.category_id.clone() == actualbudget_category_transfers_account.id.clone());
- let mut actualbudget_parent_category_transfers = actualbudget_category_transfers.to_vec();
- actualbudget_parent_category_transfers.retain(|t| t.is_parent);
- let mut actualbudget_child_category_transfers = actualbudget_category_transfers.to_vec();
- actualbudget_child_category_transfers.retain(|t| t.is_child);
-
- for actualbudget_parent_category_transfer in actualbudget_parent_category_transfers {
- let mut actualbudget_child_category_transfers =
- actualbudget_child_category_transfers.to_vec();
- actualbudget_child_category_transfers.retain(|t| {
- t.parent_id
- .clone()
- .is_some_and(|parent_id| parent_id == actualbudget_parent_category_transfer.id)
- });
-
- if actualbudget_child_category_transfers.len() != 2 {
- panic!("Category transfers should always have exactly two children.");
- }
-
- let category_1 = actualbudget_child_category_transfers[0].clone();
- let category_2 = actualbudget_child_category_transfers[1].clone();
-
- // To avoid duplicates
- if category_1.amount >= 0 {
- continue;
- }
-
- if actualbudget_child_category_transfers[0].amount
- != -actualbudget_child_category_transfers[1].amount
- {
- panic!("Category transfer children should sum to zero.");
- }
-
- category_transfers.push(CategoryTransfer {
- id: transform_id(&actualbudget_parent_category_transfer.id),
- description: actualbudget_parent_category_transfer.notes,
- quantity: actualbudget_child_category_transfers[0]
- .amount
- .try_into()
- .unwrap(),
- from_category_id: transform_id(&category_1.id),
- to_category_id: transform_id(&category_2.id),
- });
- }
-
- category_transfers
-}