Show sums for category groups #40

Merged
jacob1123 merged 4 commits from category-group-summary into master 2022-03-14 20:15:20 +01:00
6 changed files with 68 additions and 19 deletions

View File

@ -148,3 +148,22 @@ func (q *Queries) UpdateAssignment(ctx context.Context, arg UpdateAssignmentPara
_, err := q.db.ExecContext(ctx, updateAssignment, arg.CategoryID, arg.Date, arg.Amount)
return err
}
const updateAssignmentWithDifference = `-- name: UpdateAssignmentWithDifference :exec
INSERT INTO assignments (category_id, date, amount)
VALUES($1, $2, $3)
ON CONFLICT (category_id, date)
DO
UPDATE SET amount = assignments.amount + $3
`
type UpdateAssignmentWithDifferenceParams struct {
CategoryID uuid.UUID
Date time.Time
Amount numeric.Numeric
}
func (q *Queries) UpdateAssignmentWithDifference(ctx context.Context, arg UpdateAssignmentWithDifferenceParams) error {
_, err := q.db.ExecContext(ctx, updateAssignmentWithDifference, arg.CategoryID, arg.Date, arg.Amount)
return err
}

View File

@ -30,3 +30,10 @@ VALUES($1, $2, $3)
ON CONFLICT (category_id, date)
DO
UPDATE SET amount = $3;
-- name: UpdateAssignmentWithDifference :exec
INSERT INTO assignments (category_id, date, amount)
VALUES($1, $2, $3)
ON CONFLICT (category_id, date)
DO
UPDATE SET amount = assignments.amount + $3;

View File

@ -91,12 +91,12 @@ func (ynab *YNABImport) ImportAssignments(context context.Context, r io.Reader)
continue
}
assignment := CreateAssignmentParams{
assignment := UpdateAssignmentWithDifferenceParams{
Date: date,
CategoryID: category.UUID,
Amount: amount,
}
_, err = ynab.queries.CreateAssignment(context, assignment)
err = ynab.queries.UpdateAssignmentWithDifference(context, assignment)
if err != nil {
return fmt.Errorf("save assignment %v: %w", assignment, err)
}
@ -226,7 +226,8 @@ func (ynab *YNABImport) GetTransaction(context context.Context, record []string)
}
func (ynab *YNABImport) ImportRegularTransaction(context context.Context, payeeName string,
transaction CreateTransactionParams) error {
transaction CreateTransactionParams,
) error {
payeeID, err := ynab.GetPayee(context, payeeName)
if err != nil {
return fmt.Errorf("get payee %s: %w", payeeName, err)
@ -242,7 +243,8 @@ func (ynab *YNABImport) ImportRegularTransaction(context context.Context, payeeN
func (ynab *YNABImport) ImportTransferTransaction(context context.Context, payeeName string,
transaction CreateTransactionParams, openTransfers *[]Transfer,
account *Account, amount numeric.Numeric) error {
account *Account, amount numeric.Numeric,
) error {
transferToAccountName := payeeName[11:]
transferToAccount, err := ynab.GetAccount(context, transferToAccountName)
if err != nil {

View File

@ -1,7 +1,11 @@
<script lang="ts" setup>
import { computed } from 'vue';
const props = defineProps<{ value: number | undefined }>();
const props = defineProps<{
value: number | undefined
negativeClass?: string
positiveClass?: string
}>();
const internalValue = computed(() => Number(props.value ?? 0));
@ -11,5 +15,5 @@ const formattedValue = computed(() => internalValue.value.toLocaleString(undefin
</script>
<template>
<span class="text-right" :class="internalValue < 0 ? 'negative' : ''">{{ formattedValue }} </span>
<span class="text-right" :class="internalValue < 0 ? (negativeClass ?? 'negative') : positiveClass">{{ formattedValue }} </span>
</template>

View File

@ -95,10 +95,14 @@ function assignedChanged(e : Event, category : Category){
<span class="hidden sm:block text-right">Activity</span>
<span class="hidden sm:block text-right">Available</span>
<template v-for="group in GroupsForMonth">
<a
class="text-lg font-bold col-span-2 sm:col-span-4 lg:col-span-5"
<span
class="text-lg font-bold mt-2"
@click="toggleGroup(group)"
>{{ (getGroupState(group) ? "" : "+") + " " + group.Name }}</a>
>{{ (getGroupState(group) ? "" : "+") + " " + group.Name }}</span>
<Currency :value="group.AvailableLastMonth" class="hidden lg:block mt-2" positive-class="text-slate-500" negative-class="text-red-700 dark:text-red-400" />
<Currency :value="group.Assigned" class="hidden sm:block mx-2 mt-2 text-right" positive-class="text-slate-500" negative-class="text-red-700 dark:text-red-400" />
<Currency :value="group.Activity" class="hidden sm:block mt-2" positive-class="text-slate-500" negative-class="text-red-700 dark:text-red-400" />
<Currency :value="group.Available" class="mt-2" positive-class="text-slate-500" negative-class="text-red-700 dark:text-red-400" />
<template v-for="category in GetCategories(group.Name)" v-if="getGroupState(group)">
<span class="whitespace-nowrap overflow-hidden">{{ category.Name }}</span>
<Currency :value="category.AvailableLastMonth" class="hidden lg:block" />

View File

@ -51,7 +51,7 @@ export const useAccountStore = defineStore("budget/account", {
return [...monthMap?.values() || []];
},
GetCategoryAvailable(state) {
return (category : Category) : number => {
return (category: Category): number => {
return category.AvailableLastMonth + Number(category.Assigned) + category.Activity;
}
},
@ -62,7 +62,7 @@ export const useAccountStore = defineStore("budget/account", {
GetIncomeAvailable(state) {
return (year: number, month: number) => {
const IncomeCategoryID = this.GetIncomeCategoryID;
if(IncomeCategoryID == null)
if (IncomeCategoryID == null)
return 0;
const categories = this.AllCategoriesForMonth(year, month);
@ -81,12 +81,25 @@ export const useAccountStore = defineStore("budget/account", {
if (category.ID == this.GetIncomeCategoryID)
continue;
if (category.Group != prev)
categoryGroups.push({
if (prev == undefined || category.Group != prev.Name) {
prev = {
Name: category.Group,
Expand: category.Group != "Hidden Categories",
Available: this.GetCategoryAvailable(category),
AvailableLastMonth: category.AvailableLastMonth,
Activity: category.Activity,
Assigned: category.Assigned,
}
categoryGroups.push({
...prev,
Expand: prev.Name != "Hidden Categories",
});
prev = category.Group;
} else {
categoryGroups[categoryGroups.length-1].Available += this.GetCategoryAvailable(category);
categoryGroups[categoryGroups.length-1].AvailableLastMonth += category.AvailableLastMonth;
categoryGroups[categoryGroups.length-1].Activity += category.Activity;
categoryGroups[categoryGroups.length-1].Assigned += category.Assigned;
continue;
}
}
return categoryGroups;
}
@ -142,7 +155,7 @@ export const useAccountStore = defineStore("budget/account", {
account.Transactions = transactions;
},
async FetchMonthBudget(budgetid: string, year: number, month: number) {
const result = await GET("/budget/" + budgetid + "/" + year + "/" + (month+1));
const result = await GET("/budget/" + budgetid + "/" + year + "/" + (month + 1));
const response = await result.json();
if (response.Categories == undefined || response.Categories.length <= 0)
return;
@ -153,7 +166,7 @@ export const useAccountStore = defineStore("budget/account", {
const response = await result.json();
useBudgetsStore().MergeBudgetingData(response);
if(!isOpen) {
if (!isOpen) {
this.Accounts.delete(accountid);
}
},