Fixed category balance calculations.
This commit is contained in:
parent
1e35494f9d
commit
78ebbac9ca
|
|
@ -190,7 +190,7 @@ class SqliteTransactionCategoryRepository : TransactionCategoryRepository {
|
|||
stmt.bind(idx++, beforeTimestamp.value.toISOExtString());
|
||||
});
|
||||
}
|
||||
string query = qb.build() ~ " ORDER BY je.currency ASC, je.type ASC";
|
||||
string query = qb.build() ~ " GROUP BY je.currency, je.type ORDER BY je.currency ASC, je.type ASC";
|
||||
Statement stmt = db.prepare(query);
|
||||
qb.applyArgBindings(stmt);
|
||||
ResultRange result = stmt.execute();
|
||||
|
|
@ -202,7 +202,6 @@ class SqliteTransactionCategoryRepository : TransactionCategoryRepository {
|
|||
string journalEntryType = row.peek!(string, PeekMode.slice)(1);
|
||||
ulong amountSum = row.peek!ulong(2);
|
||||
|
||||
|
||||
TransactionCategoryBalance balance;
|
||||
if (currency.numericCode in balancesGroupedByCurrency) {
|
||||
balance = balancesGroupedByCurrency[currency.numericCode];
|
||||
|
|
|
|||
|
|
@ -187,8 +187,10 @@ export class TransactionApiClient extends ApiClient {
|
|||
return super.getJson(this.path + '/categories/' + parentId + '/children')
|
||||
}
|
||||
|
||||
getCategoryBalances(id: number): Promise<TransactionCategoryBalance[]> {
|
||||
return super.getJson(this.path + '/categories/' + id + '/balances')
|
||||
getCategoryBalances(id: number, includeChildren: boolean): Promise<TransactionCategoryBalance[]> {
|
||||
return super.getJson(
|
||||
this.path + '/categories/' + id + '/balances?includeChildren=' + includeChildren,
|
||||
)
|
||||
}
|
||||
|
||||
createCategory(data: CreateCategoryPayload): Promise<TransactionCategory> {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ watch(balancesIncludeSubcategories, async () => {
|
|||
if (!category.value) return
|
||||
balances.value = await new TransactionApiClient(getSelectedProfile(route)).getCategoryBalances(
|
||||
category.value.id,
|
||||
balancesIncludeSubcategories.value
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -49,6 +50,8 @@ async function loadCategory(id: number) {
|
|||
category.value = undefined
|
||||
parentCategory.value = undefined
|
||||
childCategories.value = []
|
||||
balances.value = []
|
||||
balancesIncludeSubcategories.value = true
|
||||
relatedTransactionsPage.value = defaultPage()
|
||||
try {
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
|
|
@ -57,7 +60,7 @@ async function loadCategory(id: number) {
|
|||
parentCategory.value = await api.getCategory(category.value.parentId)
|
||||
}
|
||||
childCategories.value = await api.getChildCategories(category.value.id)
|
||||
balances.value = await api.getCategoryBalances(category.value.id)
|
||||
balances.value = await api.getCategoryBalances(category.value.id, balancesIncludeSubcategories.value)
|
||||
await fetchPage(1)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
|
@ -84,32 +87,16 @@ async function fetchPage(pg: number) {
|
|||
}
|
||||
</script>
|
||||
<template>
|
||||
<AppPage
|
||||
v-if="category"
|
||||
:title="'Category - ' + category.name"
|
||||
>
|
||||
<AppPage v-if="category" :title="'Category - ' + category.name">
|
||||
<!-- Initial subtext with color & parent (if available). -->
|
||||
<div>
|
||||
<span
|
||||
class="category-color-indicator"
|
||||
:style="{ 'background-color': '#' + category.color }"
|
||||
></span>
|
||||
<span
|
||||
v-if="parentCategory"
|
||||
class="text-muted"
|
||||
style="vertical-align: middle"
|
||||
>
|
||||
<span class="category-color-indicator" :style="{ 'background-color': '#' + category.color }"></span>
|
||||
<span v-if="parentCategory" class="text-muted" style="vertical-align: middle">
|
||||
A subcategory of
|
||||
<RouterLink
|
||||
:to="`/profiles/${getSelectedProfile(route)}/categories/${parentCategory.id}`"
|
||||
>{{ parentCategory.name }}</RouterLink
|
||||
>.
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/categories/${parentCategory.id}`">{{
|
||||
parentCategory.name }}</RouterLink>.
|
||||
</span>
|
||||
<span
|
||||
v-if="!parentCategory"
|
||||
class="text-muted"
|
||||
style="vertical-align: middle"
|
||||
>
|
||||
<span v-if="!parentCategory" class="text-muted" style="vertical-align: middle">
|
||||
This is a top-level category.
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -121,12 +108,8 @@ async function fetchPage(pg: number) {
|
|||
<div v-if="childCategories.length > 0">
|
||||
<h3>Subcategories</h3>
|
||||
<ul>
|
||||
<li
|
||||
v-for="child in childCategories"
|
||||
:key="child.id"
|
||||
>
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/categories/${child.id}`"
|
||||
>{{ child.name }}
|
||||
<li v-for="child in childCategories" :key="child.id">
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/categories/${child.id}`">{{ child.name }}
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -135,33 +118,22 @@ async function fetchPage(pg: number) {
|
|||
<!-- Display total balances. -->
|
||||
<div v-if="balances.length > 0">
|
||||
<h3>Balances</h3>
|
||||
<div
|
||||
v-for="balance in balances"
|
||||
:key="balance.currency.code"
|
||||
>
|
||||
<div v-for="balance in balances" :key="balance.currency.code">
|
||||
USD:
|
||||
<AppBadge
|
||||
>Debits:
|
||||
<AppBadge>Debits:
|
||||
<span class="text-positive">{{ formatMoney(balance.debits, balance.currency) }}</span>
|
||||
</AppBadge>
|
||||
<AppBadge
|
||||
>Credits:
|
||||
<AppBadge>Credits:
|
||||
<span class="text-negative">{{ formatMoney(balance.credits, balance.currency) }}</span>
|
||||
</AppBadge>
|
||||
<AppBadge
|
||||
>Balance:
|
||||
<span
|
||||
:class="{ 'text-positive': balance.balance > 0, 'text-negative': balance.balance < 0 }"
|
||||
>{{ formatMoney(balance.balance, balance.currency) }}</span
|
||||
></AppBadge
|
||||
>
|
||||
<AppBadge>Balance:
|
||||
<span :class="{ 'text-positive': balance.balance > 0, 'text-negative': balance.balance < 0 }">{{
|
||||
formatMoney(balance.balance, balance.currency) }}</span>
|
||||
</AppBadge>
|
||||
</div>
|
||||
<FormGroup>
|
||||
<FormControl label="Include Subcategories">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="balancesIncludeSubcategories"
|
||||
/>
|
||||
<FormControl label="Include Subcategories" v-if="childCategories.length > 0">
|
||||
<input type="checkbox" v-model="balancesIncludeSubcategories" />
|
||||
</FormControl>
|
||||
<!--
|
||||
<FormControl label="After">
|
||||
|
|
@ -179,20 +151,9 @@ async function fetchPage(pg: number) {
|
|||
<p class="text-muted font-size-small mt-0">
|
||||
Below is a list of all transactions recorded with this category, or any subcategory.
|
||||
</p>
|
||||
<PaginationControls
|
||||
:page="relatedTransactionsPage"
|
||||
@update="(pr) => fetchPage(pr.page)"
|
||||
class="align-right"
|
||||
/>
|
||||
<TransactionCard
|
||||
v-for="txn in relatedTransactionsPage.items"
|
||||
:key="txn.id"
|
||||
:tx="txn"
|
||||
/>
|
||||
<p
|
||||
v-if="relatedTransactionsPage.totalElements === 0"
|
||||
class="text-muted font-italic"
|
||||
>
|
||||
<PaginationControls :page="relatedTransactionsPage" @update="(pr) => fetchPage(pr.page)" class="align-right" />
|
||||
<TransactionCard v-for="txn in relatedTransactionsPage.items" :key="txn.id" :tx="txn" />
|
||||
<p v-if="relatedTransactionsPage.totalElements === 0" class="text-muted font-italic">
|
||||
There are no transactions linked to this category.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue