Merge pull request 'Show sums for category groups' (#40) from category-group-summary into master
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #40
This commit is contained in:
commit
984a2aa296
@ -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)
|
_, err := q.db.ExecContext(ctx, updateAssignment, arg.CategoryID, arg.Date, arg.Amount)
|
||||||
return err
|
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
|
||||||
|
}
|
||||||
|
@ -30,3 +30,10 @@ VALUES($1, $2, $3)
|
|||||||
ON CONFLICT (category_id, date)
|
ON CONFLICT (category_id, date)
|
||||||
DO
|
DO
|
||||||
UPDATE SET amount = $3;
|
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;
|
@ -91,12 +91,12 @@ func (ynab *YNABImport) ImportAssignments(context context.Context, r io.Reader)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
assignment := CreateAssignmentParams{
|
assignment := UpdateAssignmentWithDifferenceParams{
|
||||||
Date: date,
|
Date: date,
|
||||||
CategoryID: category.UUID,
|
CategoryID: category.UUID,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
}
|
}
|
||||||
_, err = ynab.queries.CreateAssignment(context, assignment)
|
err = ynab.queries.UpdateAssignmentWithDifference(context, assignment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("save assignment %v: %w", assignment, err)
|
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,
|
func (ynab *YNABImport) ImportRegularTransaction(context context.Context, payeeName string,
|
||||||
transaction CreateTransactionParams) error {
|
transaction CreateTransactionParams,
|
||||||
|
) error {
|
||||||
payeeID, err := ynab.GetPayee(context, payeeName)
|
payeeID, err := ynab.GetPayee(context, payeeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("get payee %s: %w", payeeName, err)
|
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,
|
func (ynab *YNABImport) ImportTransferTransaction(context context.Context, payeeName string,
|
||||||
transaction CreateTransactionParams, openTransfers *[]Transfer,
|
transaction CreateTransactionParams, openTransfers *[]Transfer,
|
||||||
account *Account, amount numeric.Numeric) error {
|
account *Account, amount numeric.Numeric,
|
||||||
|
) error {
|
||||||
transferToAccountName := payeeName[11:]
|
transferToAccountName := payeeName[11:]
|
||||||
transferToAccount, err := ynab.GetAccount(context, transferToAccountName)
|
transferToAccount, err := ynab.GetAccount(context, transferToAccountName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
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));
|
const internalValue = computed(() => Number(props.value ?? 0));
|
||||||
|
|
||||||
@ -11,5 +15,5 @@ const formattedValue = computed(() => internalValue.value.toLocaleString(undefin
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<span class="text-right" :class="internalValue < 0 ? 'negative' : ''">{{ formattedValue }} €</span>
|
<span class="text-right" :class="internalValue < 0 ? (negativeClass ?? 'negative') : positiveClass">{{ formattedValue }} €</span>
|
||||||
</template>
|
</template>
|
@ -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">Activity</span>
|
||||||
<span class="hidden sm:block text-right">Available</span>
|
<span class="hidden sm:block text-right">Available</span>
|
||||||
<template v-for="group in GroupsForMonth">
|
<template v-for="group in GroupsForMonth">
|
||||||
<a
|
<span
|
||||||
class="text-lg font-bold col-span-2 sm:col-span-4 lg:col-span-5"
|
class="text-lg font-bold mt-2"
|
||||||
@click="toggleGroup(group)"
|
@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)">
|
<template v-for="category in GetCategories(group.Name)" v-if="getGroupState(group)">
|
||||||
<span class="whitespace-nowrap overflow-hidden">{{ category.Name }}</span>
|
<span class="whitespace-nowrap overflow-hidden">{{ category.Name }}</span>
|
||||||
<Currency :value="category.AvailableLastMonth" class="hidden lg:block" />
|
<Currency :value="category.AvailableLastMonth" class="hidden lg:block" />
|
||||||
|
@ -51,7 +51,7 @@ export const useAccountStore = defineStore("budget/account", {
|
|||||||
return [...monthMap?.values() || []];
|
return [...monthMap?.values() || []];
|
||||||
},
|
},
|
||||||
GetCategoryAvailable(state) {
|
GetCategoryAvailable(state) {
|
||||||
return (category : Category) : number => {
|
return (category: Category): number => {
|
||||||
return category.AvailableLastMonth + Number(category.Assigned) + category.Activity;
|
return category.AvailableLastMonth + Number(category.Assigned) + category.Activity;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -62,7 +62,7 @@ export const useAccountStore = defineStore("budget/account", {
|
|||||||
GetIncomeAvailable(state) {
|
GetIncomeAvailable(state) {
|
||||||
return (year: number, month: number) => {
|
return (year: number, month: number) => {
|
||||||
const IncomeCategoryID = this.GetIncomeCategoryID;
|
const IncomeCategoryID = this.GetIncomeCategoryID;
|
||||||
if(IncomeCategoryID == null)
|
if (IncomeCategoryID == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const categories = this.AllCategoriesForMonth(year, month);
|
const categories = this.AllCategoriesForMonth(year, month);
|
||||||
@ -81,12 +81,25 @@ export const useAccountStore = defineStore("budget/account", {
|
|||||||
if (category.ID == this.GetIncomeCategoryID)
|
if (category.ID == this.GetIncomeCategoryID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (category.Group != prev)
|
if (prev == undefined || category.Group != prev.Name) {
|
||||||
categoryGroups.push({
|
prev = {
|
||||||
Name: category.Group,
|
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;
|
return categoryGroups;
|
||||||
}
|
}
|
||||||
@ -142,7 +155,7 @@ export const useAccountStore = defineStore("budget/account", {
|
|||||||
account.Transactions = transactions;
|
account.Transactions = transactions;
|
||||||
},
|
},
|
||||||
async FetchMonthBudget(budgetid: string, year: number, month: number) {
|
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();
|
const response = await result.json();
|
||||||
if (response.Categories == undefined || response.Categories.length <= 0)
|
if (response.Categories == undefined || response.Categories.length <= 0)
|
||||||
return;
|
return;
|
||||||
@ -153,7 +166,7 @@ export const useAccountStore = defineStore("budget/account", {
|
|||||||
const response = await result.json();
|
const response = await result.json();
|
||||||
useBudgetsStore().MergeBudgetingData(response);
|
useBudgetsStore().MergeBudgetingData(response);
|
||||||
|
|
||||||
if(!isOpen) {
|
if (!isOpen) {
|
||||||
this.Accounts.delete(accountid);
|
this.Accounts.delete(accountid);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user