Show symbol for accounts that haven't been recently reconciled #33

Merged
jacob1123 merged 3 commits from recently-reconciled into master 2022-03-02 20:53:41 +01:00
6 changed files with 27 additions and 8 deletions

View File

@ -5,6 +5,7 @@ package postgres
import ( import (
"context" "context"
"time"
"git.javil.eu/jacob1123/budgeteer/postgres/numeric" "git.javil.eu/jacob1123/budgeteer/postgres/numeric"
"github.com/google/uuid" "github.com/google/uuid"
@ -87,6 +88,7 @@ func (q *Queries) GetAccounts(ctx context.Context, budgetID uuid.UUID) ([]Accoun
const getAccountsWithBalance = `-- name: GetAccountsWithBalance :many const getAccountsWithBalance = `-- name: GetAccountsWithBalance :many
SELECT accounts.id, accounts.name, accounts.on_budget, SELECT accounts.id, accounts.name, accounts.on_budget,
(SELECT MAX(transactions.date) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.status = 'Reconciled')::date as last_reconciled,
(SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW())::decimal(12,2) as working_balance, (SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW())::decimal(12,2) as working_balance,
(SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status IN ('Cleared', 'Reconciled'))::decimal(12,2) as cleared_balance, (SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status IN ('Cleared', 'Reconciled'))::decimal(12,2) as cleared_balance,
(SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status = 'Reconciled')::decimal(12,2) as reconciled_balance (SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status = 'Reconciled')::decimal(12,2) as reconciled_balance
@ -99,6 +101,7 @@ type GetAccountsWithBalanceRow struct {
ID uuid.UUID ID uuid.UUID
Name string Name string
OnBudget bool OnBudget bool
LastReconciled time.Time
WorkingBalance numeric.Numeric WorkingBalance numeric.Numeric
ClearedBalance numeric.Numeric ClearedBalance numeric.Numeric
ReconciledBalance numeric.Numeric ReconciledBalance numeric.Numeric
@ -117,6 +120,7 @@ func (q *Queries) GetAccountsWithBalance(ctx context.Context, budgetID uuid.UUID
&i.ID, &i.ID,
&i.Name, &i.Name,
&i.OnBudget, &i.OnBudget,
&i.LastReconciled,
&i.WorkingBalance, &i.WorkingBalance,
&i.ClearedBalance, &i.ClearedBalance,
&i.ReconciledBalance, &i.ReconciledBalance,

View File

@ -15,6 +15,7 @@ ORDER BY accounts.name;
-- name: GetAccountsWithBalance :many -- name: GetAccountsWithBalance :many
SELECT accounts.id, accounts.name, accounts.on_budget, SELECT accounts.id, accounts.name, accounts.on_budget,
(SELECT MAX(transactions.date) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.status = 'Reconciled')::date as last_reconciled,
(SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW())::decimal(12,2) as working_balance, (SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW())::decimal(12,2) as working_balance,
(SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status IN ('Cleared', 'Reconciled'))::decimal(12,2) as cleared_balance, (SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status IN ('Cleared', 'Reconciled'))::decimal(12,2) as cleared_balance,
(SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status = 'Reconciled')::decimal(12,2) as reconciled_balance (SELECT SUM(transactions.amount) FROM transactions WHERE transactions.account_id = accounts.id AND transactions.date < NOW() AND transactions.status = 'Reconciled')::decimal(12,2) as reconciled_balance

View File

@ -41,25 +41,25 @@ function createReconcilationTransaction() {
</script> </script>
<template> <template>
<div class="grid grid-cols-2"> <div class="grid grid-cols-[1fr_auto]">
<h1 class="inline"> <h1 class="inline">
{{ accounts.CurrentAccount?.Name }} {{ accounts.CurrentAccount?.Name }}
<EditAccount /> <EditAccount />
</h1> </h1>
<div class="text-right"> <div class="text-right flex flex-wrap flex-col md:flex-row justify-end gap-2 max-w-sm">
<span class="border-2 rounded-lg p-1 whitespace-nowrap"> <span class="border-2 rounded-lg p-1 whitespace-nowrap flex-1">
Working: Working:
<Currency :value="accounts.CurrentAccount?.WorkingBalance" /> <Currency :value="accounts.CurrentAccount?.WorkingBalance" />
</span> </span>
<span class="border-2 rounded-lg p-1 ml-2 whitespace-nowrap"> <span class="border-2 rounded-lg p-1 whitespace-nowrap flex-1">
Cleared: Cleared:
<Currency :value="accounts.CurrentAccount?.ClearedBalance" /> <Currency :value="accounts.CurrentAccount?.ClearedBalance" />
</span> </span>
<span <span
class="border-2 border-blue-500 rounded-lg bg-blue-500 ml-2 p-1 whitespace-nowrap" class="border-2 border-blue-500 rounded-lg bg-blue-500 p-1 whitespace-nowrap flex-1"
v-if="!transactions.Reconciling" v-if="!transactions.Reconciling"
@click="transactions.Reconciling = true" @click="transactions.Reconciling = true"
> >

View File

@ -2,7 +2,7 @@
import { computed } from "vue"; import { computed } from "vue";
import Currency from "../components/Currency.vue" import Currency from "../components/Currency.vue"
import { useBudgetsStore } from "../stores/budget" import { useBudgetsStore } from "../stores/budget"
import { useAccountStore } from "../stores/budget-account" import { Account, useAccountStore } from "../stores/budget-account"
import { useSettingsStore } from "../stores/settings" import { useSettingsStore } from "../stores/settings"
const ExpandMenu = computed(() => useSettingsStore().Menu.Expand); const ExpandMenu = computed(() => useSettingsStore().Menu.Expand);
@ -16,6 +16,18 @@ const OnBudgetAccounts = computed(() => accountStore.OnBudgetAccounts);
const OffBudgetAccounts = computed(() => accountStore.OffBudgetAccounts); const OffBudgetAccounts = computed(() => accountStore.OffBudgetAccounts);
const OnBudgetAccountsBalance = computed(() => accountStore.OnBudgetAccountsBalance); const OnBudgetAccountsBalance = computed(() => accountStore.OnBudgetAccountsBalance);
const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBalance); const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBalance);
function isRecentlyReconciled(account : Account) {
const now = new Date().getTime();
const recently = 7 * 24 * 60 * 60 * 1000;
console.log(account.Name, account.LastReconciled, now, recently, new Date(now-recently));
return new Date(now - recently).getTime() < account.LastReconciled.getTime();
}
function getAccountName(account : Account) {
const reconciledMarker = isRecentlyReconciled(account) ? "" : " *";
return account.Name + reconciledMarker;
}
</script> </script>
<template> <template>
@ -35,7 +47,7 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa
<Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="OnBudgetAccountsBalance" /> <Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="OnBudgetAccountsBalance" />
</div> </div>
<div v-for="account in OnBudgetAccounts" class="flex flex-row justify-between"> <div v-for="account in OnBudgetAccounts" class="flex flex-row justify-between">
<router-link :to="'/budget/'+CurrentBudgetID+'/account/'+account.ID">{{account.Name}}</router-link> <router-link :to="'/budget/'+CurrentBudgetID+'/account/'+account.ID">{{getAccountName(account)}}</router-link>
<Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="account.ClearedBalance" /> <Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="account.ClearedBalance" />
</div> </div>
</li> </li>
@ -45,7 +57,7 @@ const OffBudgetAccountsBalance = computed(() => accountStore.OffBudgetAccountsBa
<Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="OffBudgetAccountsBalance" /> <Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="OffBudgetAccountsBalance" />
</div> </div>
<div v-for="account in OffBudgetAccounts" class="flex flex-row justify-between"> <div v-for="account in OffBudgetAccounts" class="flex flex-row justify-between">
<router-link :to="'/budget/'+CurrentBudgetID+'/account/'+account.ID">{{account.Name}}</router-link> <router-link :to="'/budget/'+CurrentBudgetID+'/account/'+account.ID">{{getAccountName(account)}}</router-link>
<Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="account.ClearedBalance" /> <Currency :class="ExpandMenu?'md:inline':'md:hidden'" :value="account.ClearedBalance" />
</div> </div>
</li> </li>

View File

@ -20,6 +20,7 @@ export interface Account {
WorkingBalance: number WorkingBalance: number
ReconciledBalance: number ReconciledBalance: number
Transactions: string[] Transactions: string[]
LastReconciled: Date
} }
export interface Category { export interface Category {

View File

@ -58,6 +58,7 @@ export const useBudgetsStore = defineStore('budget', {
for (const account of response.Accounts || []) { for (const account of response.Accounts || []) {
const existingAccount = accounts.Accounts.get(account.ID); const existingAccount = accounts.Accounts.get(account.ID);
account.Transactions = existingAccount?.Transactions ?? []; account.Transactions = existingAccount?.Transactions ?? [];
account.LastReconciled = new Date(account.LastReconciled);
accounts.Accounts.set(account.ID, account); accounts.Accounts.set(account.ID, account);
} }
for (const category of response.Categories || []) { for (const category of response.Categories || []) {