Skip to content

Commit

Permalink
v1.0.22 - Add currency conversion for Months view (#22)
Browse files Browse the repository at this point in the history
* v1.0.22 - Fix accounts UI bug

* v1.0.22 - Add date to forex transaction

* v1.0.22 - Reduce code

* v1.0.22 - Move errorDialog

* v1.0.22 - Use ECB Rate option

* v1.0.22 - Use arguments in SQL

* v1.0.22 - Simplify SQL

* v1.0.22 - Use currency table

* v1.0.22 - Make date same

* v1.0.22 - Fix forex consolidation issues

* v1.0.22 - Add rates table
  • Loading branch information
Donnie committed Jan 24, 2024
1 parent 7609769 commit 8fb5d6a
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 86 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<a href="https://flutter.dev/" style="text-decoration:none" area-label="flutter">
<img src="https://img.shields.io/badge/Platform-Flutter%203.16.5-blue">
</a>
<a href="https://github.com/Donnie/Finease/releases/tag/v1.0.21" style="text-decoration:none" area-label="flutter">
<img src="https://img.shields.io/badge/Version-1.0.21-orange">
<a href="https://github.com/Donnie/Finease/releases/tag/v1.0.22" style="text-decoration:none" area-label="flutter">
<img src="https://img.shields.io/badge/Version-1.0.22-orange">
</a>
<a href="https://github.com/Donnie/Finease/actions/workflows/android_release.yml" style="text-decoration:none" area-label="flutter">
<img src="https://github.com/Donnie/Finease/actions/workflows/android_release.yml/badge.svg">
Expand Down
20 changes: 20 additions & 0 deletions lib/db/currency.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'package:finease/core/export.dart';
import 'package:finease/db/db.dart';
import 'package:finease/db/settings.dart';
import 'package:hive/hive.dart';
import 'package:sqflite/sqflite.dart';

class CurrencyBoxService {
final DatabaseHelper _databaseHelper = DatabaseHelper();
static const String _boxName = 'currencies';
late Box _box;
late String prefCurrency;
Expand Down Expand Up @@ -32,6 +35,23 @@ class CurrencyBoxService {
}
}

Future<void> updateRatesTable() async {
final dbClient = await _databaseHelper.db;
Batch batch = dbClient.batch();

for (var currency in _box.keys) {
if (currency == "lastUpdate") break;
final rate = _box.get(currency);
batch.insert(
'rates',
{'currency': currency, 'rate': rate},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}

await batch.commit(noResult: true);
}

Future<double> getSingleRate(
String baseCurrency,
String targetCurrency,
Expand Down
5 changes: 3 additions & 2 deletions lib/db/db.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:finease/db/migrations/a_initial_migration.dart';
import 'package:finease/db/migrations/b_add_indices.dart';
import 'package:finease/db/migrations/c_add_rates.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:io';
Expand Down Expand Up @@ -39,7 +40,7 @@ class DatabaseHelper {
Future<Database> initDb(String path) async {
var ourDb = await openDatabase(
path,
version: 2,
version: 3,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
Expand All @@ -55,7 +56,7 @@ class DatabaseHelper {
await bAddIndices(db);
}
if (oldVersion < 3) {
// Execute next migration
await cAddRates(db);
}
}

Expand Down
22 changes: 13 additions & 9 deletions lib/db/entries.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ class EntryService {
.createForexAccountIfNotExist(creditAccount!.currency);

await createEntry(Entry(
debitAccountId: entry.debitAccountId,
creditAccountId: forexAccountDebit.id!,
amount: debitAmount,
notes: "Forex transaction by App",
creditAccountId: forexAccountDebit.id!,
date: entry.date,
debitAccountId: entry.debitAccountId,
notes: "Forex transaction",
));

await createEntry(Entry(
debitAccountId: forexAccountCredit.id!,
creditAccountId: entry.creditAccountId,
amount: entry.amount,
creditAccountId: entry.creditAccountId,
date: entry.date,
debitAccountId: forexAccountCredit.id!,
notes: entry.notes,
));
}
Expand All @@ -63,16 +65,18 @@ class EntryService {
.createForexAccountIfNotExist(creditAccount.currency);

await createEntry(Entry(
debitAccountId: entry.debitAccountId,
creditAccountId: forexAccountDebit.id!,
amount: debitAmount,
creditAccountId: forexAccountDebit.id!,
date: entry.date,
debitAccountId: entry.debitAccountId,
notes: "Forex transaction by App",
));

await createEntry(Entry(
debitAccountId: forexAccountCredit.id!,
creditAccountId: entry.creditAccountId,
amount: entry.amount,
creditAccountId: entry.creditAccountId,
date: entry.date,
debitAccountId: forexAccountCredit.id!,
notes: entry.notes,
));
}
Expand Down
10 changes: 10 additions & 0 deletions lib/db/migrations/c_add_rates.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:sqflite/sqflite.dart';

Future<void> cAddRates(Database db) async {
await db.execute('''
CREATE TABLE IF NOT EXISTS rates (
currency TEXT PRIMARY KEY,
rate DECIMAL(10, 6) NOT NULL
);
''');
}
107 changes: 80 additions & 27 deletions lib/db/months.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:finease/db/db.dart';
import 'package:finease/db/currency.dart';
import 'package:finease/db/settings.dart';

class MonthService {
final DatabaseHelper _databaseHelper;
final CurrencyBoxService currencyBoxService = CurrencyBoxService();

MonthService({DatabaseHelper? databaseHelper})
: _databaseHelper = databaseHelper ?? DatabaseHelper();
Expand All @@ -11,50 +13,95 @@ class MonthService {
String prefCurrency =
await SettingService().getSetting(Setting.prefCurrency);

await currencyBoxService.init();
await currencyBoxService.updateRatesTable();

final dbClient = await _databaseHelper.db;
final results = await dbClient.rawQuery('''
String query = '''
WITH RECURSIVE MonthDates(monthDate) AS (
SELECT DATETIME((SELECT MIN(date) FROM entries), 'start of month')
UNION ALL
SELECT DATETIME(monthDate, '+1 month')
FROM MonthDates
WHERE DATETIME(monthDate, '+1 month') < CURRENT_DATE
),
ForexPairs AS (
SELECT
MIN(e.id) AS forex_debit_id,
MAX(e.id) AS forex_credit_id
FROM
entries e
INNER JOIN accounts a ON e.credit_account_id = a.id OR e.debit_account_id = a.id
WHERE
a.name = 'Forex'
GROUP BY
e.date
),
ConsolidatedForex AS (
SELECT
f.forex_debit_id AS id,
e1.created_at,
e1.updated_at,
e1.debit_account_id,
e2.credit_account_id,
e2.amount,
e1.date,
e2.notes
FROM
ForexPairs f
JOIN entries e1 ON f.forex_debit_id = e1.id
JOIN entries e2 ON f.forex_credit_id = e2.id
),
NonForexEntries AS (
SELECT *
FROM entries
WHERE id NOT IN (SELECT forex_debit_id FROM ForexPairs)
AND id NOT IN (SELECT forex_credit_id FROM ForexPairs)
),
ConsolidatedEntries AS (
SELECT *
FROM ConsolidatedForex
UNION ALL
SELECT *
FROM NonForexEntries
),
MonthlyTotals AS (
SELECT
SELECT
months.startDate,
months.endDate,
COALESCE((
SELECT
SUM(e.amount)
FROM entries AS e
LEFT JOIN accounts AS ac ON e.credit_account_id = ac.id
LEFT JOIN accounts AS ad ON e.debit_account_id = ad.id
WHERE
ac.type IN ('asset', 'liability') AND ad.type IN ('income', 'expense')
AND e.date BETWEEN months.startDate AND months.endDate
AND ac.currency = '$prefCurrency'
AND ad.currency = '$prefCurrency'
COALESCE(SUM(
CASE
WHEN ac.currency = ? THEN e.amount
ELSE e.amount / (
SELECT cr.rate FROM rates cr
WHERE cr.currency = ac.currency
)
END
) FILTER (
WHERE ac.type IN ('asset', 'liability') AND ad.type IN ('income', 'expense')
), 0) AS income,
COALESCE((
SELECT
SUM(e.amount)
FROM entries AS e
LEFT JOIN accounts AS ac ON e.credit_account_id = ac.id
LEFT JOIN accounts AS ad ON e.debit_account_id = ad.id
WHERE
ad.type IN ('asset', 'liability') AND ac.type IN ('income', 'expense')
AND e.date BETWEEN months.startDate AND months.endDate
AND ac.currency = '$prefCurrency'
AND ad.currency = '$prefCurrency'
COALESCE(SUM(
CASE
WHEN ac.currency = ? THEN e.amount
ELSE e.amount / (
SELECT cr.rate FROM rates cr
WHERE cr.currency = ac.currency
)
END
) FILTER (
WHERE ad.type IN ('asset', 'liability') AND ac.type IN ('income', 'expense')
), 0) AS expense,
'$prefCurrency' AS currency
? AS currency
FROM (
SELECT
REPLACE(DATETIME(monthDate, 'start of month'), ' ', 'T') || 'Z' as startDate,
REPLACE(DATETIME(monthDate, 'start of month', '+1 month', '-1 second'), ' ', 'T') || 'Z' as endDate
FROM MonthDates
) AS months
LEFT JOIN ConsolidatedEntries e ON e.date BETWEEN months.startDate AND months.endDate
LEFT JOIN accounts ac ON e.credit_account_id = ac.id
LEFT JOIN accounts ad ON e.debit_account_id = ad.id
GROUP BY months.startDate, months.endDate
),
CumulativeTotals AS (
SELECT
Expand All @@ -74,7 +121,13 @@ class MonthService {
networth,
currency
FROM CumulativeTotals;
''');
''';

final results = await dbClient.rawQuery(
query,
[prefCurrency, prefCurrency, prefCurrency],
);
currencyBoxService.close();

try {
return results.map((json) => Month.fromJson(json)).toList();
Expand Down Expand Up @@ -128,5 +181,5 @@ class Month {
return (incomeSquared / (incomeSquared + expenseSquared));
}

bool get good => factor > 0.5;
bool get good => factor > 0.5;
}
1 change: 0 additions & 1 deletion lib/pages/add_account/main.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:finease/core/export.dart';
import 'package:finease/db/accounts.dart';
import 'package:finease/pages/export.dart';
import 'package:finease/parts/error_dialog.dart';
import 'package:finease/parts/export.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
Expand Down
Loading

0 comments on commit 8fb5d6a

Please sign in to comment.