diff --git a/package-lock.json b/package-lock.json index c84a229..8176700 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@auth/sveltekit": "^1.10.0", "@tailwindcss/vite": "^4.1.11", "cron": "^4.3.2", + "echarts": "^5.6.0", "patchright": "^1.52.5", "postgres": "^3.4.7", "puppeteer": "^24.14.0", @@ -3934,6 +3935,20 @@ "node": ">= 0.4" } }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -8475,6 +8490,19 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" } } } diff --git a/package.json b/package.json index 4401fa6..9ed9469 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@auth/sveltekit": "^1.10.0", "@tailwindcss/vite": "^4.1.11", "cron": "^4.3.2", + "echarts": "^5.6.0", "patchright": "^1.52.5", "postgres": "^3.4.7", "puppeteer": "^24.14.0", diff --git a/src/lib/db.js b/src/lib/db.js index d3c9e8b..903a1c6 100644 --- a/src/lib/db.js +++ b/src/lib/db.js @@ -86,7 +86,7 @@ export async function updateBudget(id, name, amount, notes) { return result; } -export async function getBudgetTransactions(id) { +export async function getBudgetTransactionsByid(id) { // Fetch all transactions associated with a specific budget try { let transactions = await db` @@ -258,6 +258,22 @@ export async function getBudgetTransactionsForAccount(accountID) { return transactions; } +export async function getAllBudgetTransactions(accountID) { + const transactions = await db` + select budget_transaction.id as id, + budget_transaction.budget_id as budget_id, + budget_transaction.transaction_id as transaction_id, + budget_transaction.amount as amount, + budget_transaction.notes as notes, + budget.name as budget_name + from budget_transaction + join transaction on budget_transaction.transaction_id = transaction.id + join budget on budget_transaction.budget_id = budget.id + `; + return transactions; +} + + export async function getHiddenAccounts(age) { const accounts = await db` select @@ -514,4 +530,63 @@ export async function runRules() { } } +export async function getUnallocatedTotal() { + const result = await db` + select sum(amount) as total + from budget_transaction + where transaction_id is null + `; + // result = Result [{ total: 1000.00 }] + return result[0].total; +} + +export async function getUnallocatedTransactions() { + const result = await db` + SELECT TRANSACTION.id as id, + TRANSACTION.amount as amount, + TRANSACTION.description as description, + TRANSACTION.date as date, + TRANSACTION.account_id + FROM TRANSACTION + full join budget_transaction + ON TRANSACTION.id = budget_transaction.transaction_id + WHERE budget_transaction.amount IS NULL + AND TRANSACTION.out_of_budget = FALSE + `; + // result = Result [{ id: 1, amount: 100.00, notes: "Unallocated funds" }, ...] + return result; +} + +export async function getUnderallocatedTransactions() { + const result = await db` + SELECT * + FROM (SELECT TRANSACTION.id, + TRANSACTION.amount AS amount, + TRANSACTION.description, + TRANSACTION.DATE AS date, + TRANSACTION.account_id, + SUM(budget_transaction.amount) AS budget_total + FROM TRANSACTION + full join budget_transaction + ON TRANSACTION.id = budget_transaction.transaction_id + WHERE TRANSACTION.out_of_budget = FALSE + GROUP BY TRANSACTION.id) AS t + WHERE t.amount != t.budget_total + `; + // result = Result [{ id: 1, amount: 100.00, notes: "Unallocated funds" }, ...] + return result; +} + +export async function getLast30DaysTransactionsSums() { + let result = await db` + SELECT cast(date as date) as date, SUM(amount) + from transaction + where date >= (CURRENT_DATE - interval '30 days') + GROUP BY cast(date as date) + order by date desc; + `; + // result = Result [{ id: 1, amount: 100.00, notes: "Recent transaction" }, ...] + return result; +} + export default db; diff --git a/src/lib/echarts.js b/src/lib/echarts.js new file mode 100644 index 0000000..bbf7978 --- /dev/null +++ b/src/lib/echarts.js @@ -0,0 +1,6 @@ +import * as charts from 'echarts'; + +export function echarts(node, option) { + const chart = charts.init(node); + chart.setOption(option); +} \ No newline at end of file diff --git a/src/lib/editTransaction.svelte b/src/lib/editTransaction.svelte new file mode 100644 index 0000000..2728c7c --- /dev/null +++ b/src/lib/editTransaction.svelte @@ -0,0 +1,128 @@ + + + diff --git a/src/lib/transactionList.svelte b/src/lib/transactionList.svelte new file mode 100644 index 0000000..bfbf574 --- /dev/null +++ b/src/lib/transactionList.svelte @@ -0,0 +1,80 @@ + + +