Rebuild transaction list.

This commit is contained in:
James Cole 2021-09-17 07:18:37 +02:00
parent f95a064eca
commit 0e5256c8ce
No known key found for this signature in database
GPG Key ID: BDE6667570EADBD5
7 changed files with 256 additions and 146 deletions

View File

@ -196,7 +196,6 @@ export default {
endStr = format(this.urlEnd, 'y-MM-dd');
}
let url = './api/v1/transactions?type=' + this.type + '&page=' + page + "&start=" + startStr + "&end=" + endStr + '&cache=' + this.cacheKey;
url = './api/v1/transactions?type=' + this.type + '&page=' + page + '&cache=' + this.cacheKey;
api.get(url)
.then(response => {
//let currentPage = parseInt(response.data.meta.pagination.current_page);
@ -218,73 +217,73 @@ export default {
);
});
},
createTransactionRows: function () {
this.transactionRows = [];
for (let i in this.transactions) {
let transaction = this.transactions[i];
let transactionRow = this.getTransactionRow(transaction, 0);
this.transactionRows.push(transactionRow);
if (transaction.attributes.transactions.length > 1) {
transactionRow.description = transaction.attributes.group_title;
transactionRow.split = true;
transactionRow.collapsed = transaction.collapsed === true || transaction.collapsed === undefined;
transactionRow.amount = transaction.attributes.transactions
.map(transaction => Number(transaction.amount))
.reduce((sum, n) => sum + n);
transactionRow.source_name = '';
transactionRow.source_id = '';
transactionRow.destination_name = '';
transactionRow.destination_id = '';
if (!transactionRow.collapsed) {
for (let i = 0; i < transaction.attributes.transactions.length; i++) {
let splitTransactionRow = this.getTransactionRow(transaction, i);
splitTransactionRow.key = splitTransactionRow.id + "." + i
splitTransactionRow.split = true;
splitTransactionRow.split_index = i + 1;
splitTransactionRow.split_parent = transactionRow;
this.transactionRows.push(splitTransactionRow);
}
}
}
}
this.loading = false;
},
getTransactionRow(transaction, index) {
let transactionRow = {};
let currentTransaction = transaction.attributes.transactions[index];
transactionRow.key = transaction.id;
transactionRow.id = transaction.id;
transactionRow.type = currentTransaction.type;
transactionRow.description = currentTransaction.description;
transactionRow.amount = currentTransaction.amount;
transactionRow.currency_code = currentTransaction.currency_code;
transactionRow.date = new Date(currentTransaction.date);
transactionRow.date_formatted = format(transactionRow.date, this.$t('config.month_and_day_fns'));
transactionRow.source_name = currentTransaction.source_name;
transactionRow.source_id = currentTransaction.source_id;
transactionRow.destination_name = currentTransaction.destination_name;
transactionRow.destination_id = currentTransaction.destination_id;
transactionRow.category_id = currentTransaction.category_id;
transactionRow.category_name = currentTransaction.category_name;
transactionRow.split = false;
transactionRow.split_index = 0;
transactionRow.split_parent = null;
return transactionRow;
},
toggleCollapse: function (row) {
let transaction = this.transactions.filter(transaction => transaction.id === row.id)[0];
if (transaction.collapsed === undefined) {
transaction.collapsed = false;
} else {
transaction.collapsed = !transaction.collapsed;
}
this.createTransactionRows();
},
// createTransactionRows: function () {
// this.transactionRows = [];
// for (let i in this.transactions) {
// let transaction = this.transactions[i];
// let transactionRow = this.getTransactionRow(transaction, 0);
// this.transactionRows.push(transactionRow);
//
// if (transaction.attributes.transactions.length > 1) {
// transactionRow.description = transaction.attributes.group_title;
// transactionRow.split = true;
// transactionRow.collapsed = transaction.collapsed === true || transaction.collapsed === undefined;
// transactionRow.amount = transaction.attributes.transactions
// .map(transaction => Number(transaction.amount))
// .reduce((sum, n) => sum + n);
// transactionRow.source_name = '';
// transactionRow.source_id = '';
// transactionRow.destination_name = '';
// transactionRow.destination_id = '';
//
// if (!transactionRow.collapsed) {
// for (let i = 0; i < transaction.attributes.transactions.length; i++) {
// let splitTransactionRow = this.getTransactionRow(transaction, i);
// splitTransactionRow.key = splitTransactionRow.id + "." + i
// splitTransactionRow.split = true;
// splitTransactionRow.split_index = i + 1;
// splitTransactionRow.split_parent = transactionRow;
// this.transactionRows.push(splitTransactionRow);
// }
// }
// }
// }
//
// this.loading = false;
// },
// getTransactionRow(transaction, index) {
// let transactionRow = {};
// let currentTransaction = transaction.attributes.transactions[index];
//
// transactionRow.key = transaction.id;
// transactionRow.id = transaction.id;
// transactionRow.type = currentTransaction.type;
// transactionRow.description = currentTransaction.description;
// transactionRow.amount = currentTransaction.amount;
// transactionRow.currency_code = currentTransaction.currency_code;
// transactionRow.date = new Date(currentTransaction.date);
// transactionRow.date_formatted = format(transactionRow.date, this.$t('config.month_and_day_fns'));
// transactionRow.source_name = currentTransaction.source_name;
// transactionRow.source_id = currentTransaction.source_id;
// transactionRow.destination_name = currentTransaction.destination_name;
// transactionRow.destination_id = currentTransaction.destination_id;
// transactionRow.category_id = currentTransaction.category_id;
// transactionRow.category_name = currentTransaction.category_name;
// transactionRow.split = false;
// transactionRow.split_index = 0;
// transactionRow.split_parent = null;
//
// return transactionRow;
// },
// toggleCollapse: function (row) {
// let transaction = this.transactions.filter(transaction => transaction.id === row.id)[0];
// if (transaction.collapsed === undefined) {
// transaction.collapsed = false;
// } else {
// transaction.collapsed = !transaction.collapsed;
// }
// this.createTransactionRows();
// },
},
}

View File

@ -30,7 +30,6 @@
Loading: {{ loading }}<br>
<BPagination v-if="!loading"
v-model="currentPage"
@change="currentPage = $event"
:total-rows="total"
:per-page="perPage"
aria-controls="my-table"
@ -59,45 +58,84 @@
<span class="fa fa-spinner fa-spin"></span>
</template>
<template #cell(type)="data">
<span v-if="! data.item.split || data.item.split_parent === null">
<span v-if="!data.item.dummy">
<span class="fas fa-long-arrow-alt-right" v-if="'deposit' === data.item.type"></span>
<span class="fas fa-long-arrow-alt-left" v-else-if="'withdrawal' === data.item.type"></span>
<span class="fas fa-long-arrows-alt-h" v-else-if="'transfer' === data.item.type"></span>
</span>
</template>
<template #cell(description)="data">
<span class="fas fa-angle-right" v-if="data.item.split && data.item.split_parent !== null"></span>
<a :class="false === data.item.active ? 'text-muted' : ''" :href="'./transactions/show/' + data.item.id" :title="data.value">{{
data.value
}}</a>
<span class="fa fa-spinner fa-spin" v-if="data.item.dummy"></span>
<span v-if="!data.item.split">
<a :href="'./transactions/show/' + data.item.id" :title="data.value">
{{ data.item.description }}
</a>
</span>
<span v-if="data.item.split">
<!-- title first -->
<span class="fas fa-angle-right" @click="toggleCollapse(data.item.id)" style="cursor: pointer;"></span>
<a :href="'./transactions/show/' + data.item.id" :title="data.value">
{{ data.item.description }}
</a><br />
<span v-if="!data.item.collapsed">
<span v-for="(split, index) in data.item.splits" v-bind:key="index">
&nbsp; &nbsp; {{ split.description }}<br />
</span>
</span>
</span>
</template>
<template #cell(amount)="data">
<span class="text-success" v-if="'deposit' === data.item.type">
<!-- row amount first (3x) -->
<span :class="'text-success ' + (!data.item.collapsed ? 'font-weight-bold' : '')" v-if="'deposit' === data.item.type">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: data.item.currency_code}).format(data.item.amount) }}
</span>
<span class="text-danger" v-else-if="'withdrawal' === data.item.type">
<span :class="'text-danger ' + (!data.item.collapsed ? 'font-weight-bold' : '')" v-if="'withdrawal' === data.item.type">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: data.item.currency_code}).format(-data.item.amount) }}
</span>
<span class="text-muted" v-else-if="'transfer' === data.item.type">
<span :class="'text-muted ' + (!data.item.collapsed ? 'font-weight-bold' : '')" v-if="'transfer' === data.item.type">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: data.item.currency_code}).format(data.item.amount) }}
</span>
<br />
<!-- splits -->
<span v-if="!data.item.collapsed">
<span v-for="(split, index) in data.item.splits" v-bind:key="index">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: split.currency_code}).format(split.amount) }}<br />
</span>
</span>
</template>
<template #cell(date)="data">
{{ data.item.date_formatted }}
</template>
<template #cell(source_account)="data">
<a :class="false === data.item.active ? 'text-muted' : ''" :href="'./accounts/show/' + data.item.source_id"
:title="data.item.source_name">{{ data.item.source_name }}</a>
<!-- extra break for splits -->
<span v-if="true===data.item.split && !data.item.collapsed">
<br />
</span>
<em v-if="true===data.item.split && data.item.collapsed">
...
</em>
<!-- loop all accounts, hidden if split -->
<span v-for="(split, index) in data.item.splits" v-bind:key="index" v-if="false===data.item.split || (true===data.item.split && !data.item.collapsed)">
<a :href="'./accounts/show/' + split.source_id" :title="split.source_name">{{ split.source_name }}</a><br />
</span>
</template>
<template #cell(destination_account)="data">
<a :class="false === data.item.active ? 'text-muted' : ''" :href="'./accounts/show/' + data.item.destination_id"
:title="data.item.destination_name">{{ data.item.destination_name }}</a>
<!-- extra break for splits -->
<span v-if="true===data.item.split && !data.item.collapsed">
<br />
</span>
<em v-if="true===data.item.split && data.item.collapsed">
...
</em>
<!-- loop all accounts, hidden if split -->
<span v-for="(split, index) in data.item.splits" v-bind:key="index" v-if="false===data.item.split || (true===data.item.split && !data.item.collapsed)">
<a :href="'./accounts/show/' + split.destination_id" :title="split.destination_name">{{ split.destination_name }}</a><br />
</span>
</template>
<template #cell(menu)="data">
<div class="btn-group btn-group-sm" v-if="! data.item.split || data.item.split_parent === null">
<div class="btn-group btn-group-sm">
<div class="dropdown">
<button class="btn btn-light btn-sm dropdown-toggle" type="button" :id="'dropdownMenuButton' + data.item.id" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
@ -113,19 +151,20 @@
</div>
</div>
</div>
<div class="btn btn-light btn-sm" v-if="data.item.split && data.item.split_parent === null && data.item.collapsed === true"
v-on:click="toggleCollapse(data.item)">
<span class="fa fa-caret-down"></span>
{{ $t('firefly.transaction_expand_split') }}
</div>
<div class="btn btn-light btn-sm" v-else-if="data.item.split && data.item.split_parent === null && data.item.collapsed === false"
v-on:click="toggleCollapse(data.item)">
<span class="fa fa-caret-up"></span>
{{ $t('firefly.transaction_collapse_split') }}
</div>
</template>
<template #cell(category)="data">
{{ data.item.category_name }}
<template #cell(category_name)="data">
<!-- extra break for splits -->
<span v-if="true===data.item.split && !data.item.collapsed">
<br />
</span>
<em v-if="true===data.item.split && data.item.collapsed">
...
</em>
<!-- loop all categories, hidden if split -->
<span v-for="(split, index) in data.item.splits" v-bind:key="index" v-if="false===data.item.split || (true===data.item.split && !data.item.collapsed)">
<a :href="'./categories/show/' + split.category_id" :title="split.category_name">{{ split.category_name }}</a><br />
</span>
</template>
</BTable>
@ -313,25 +352,34 @@ export default {
methods: {
...mapMutations('root', ['refreshCacheKey',]),
toggleCollapse: function (row) {
let transaction = this.entries.filter(transaction => transaction.id === row.id)[0];
if (transaction.collapsed === undefined) {
transaction.collapsed = false;
} else {
transaction.collapsed = !transaction.collapsed;
}
this.parseTransactions();
},
// toggleCollapse: function (row) {
// let transaction = this.entries.filter(transaction => transaction.id === row.id)[0];
// if (transaction.collapsed === undefined) {
// transaction.collapsed = false;
// } else {
// transaction.collapsed = !transaction.collapsed;
// }
// this.parseTransactions();
// },
parseTransactions: function () {
console.log('parseTransactions. Count is ' + this.entries.length + ' and page is ' + this.page);
if (0 === this.entries.length) {
return;
}
console.log('Now have ' + this.transactions.length + ' transactions');
for (let i = 0; i < this.total; i++) {
this.transactions.push({dummy: true});
}
console.log('Generated ' + this.total + ' dummies');
console.log('Now have ' + this.transactions.length + ' transactions');
let index = (this.page - 1) * this.perPage;
for (let i in this.entries) {
let transaction = this.entries[i];
this.transactions[index] = this.getTransactionRow(transaction, 0);
// build split
this.transactions[index] = this.parseTransaction(transaction);
//this.transactions[index] = this.getTransactionRow(transaction, 0);
// this code will not be used for the time being.
// if (transaction.attributes.transactions.length > 1) {
@ -362,6 +410,9 @@ export default {
// }
index++;
}
console.log('Added ' + this.entries.length + ' entries');
console.log('Now have ' + this.transactions.length + ' transactions');
this.loading = false;
},
@ -381,30 +432,90 @@ export default {
{key: 'menu', label: ' ', sortable: false},
];
},
getTransactionRow(transaction, index) {
let transactionRow = {};
let currentTransaction = transaction.attributes.transactions[index];
/**
* Parse a single transaction.
* @param transaction
*/
parseTransaction: function (transaction) {
let row = {};
transactionRow.key = transaction.id;
transactionRow.id = transaction.id;
transactionRow.type = currentTransaction.type;
transactionRow.description = currentTransaction.description;
transactionRow.amount = currentTransaction.amount;
transactionRow.currency_code = currentTransaction.currency_code;
transactionRow.date = new Date(currentTransaction.date);
transactionRow.date_formatted = format(transactionRow.date, this.$t('config.month_and_day_fns'));
transactionRow.source_name = currentTransaction.source_name;
transactionRow.source_id = currentTransaction.source_id;
transactionRow.destination_name = currentTransaction.destination_name;
transactionRow.destination_id = currentTransaction.destination_id;
transactionRow.category_id = currentTransaction.category_id;
transactionRow.category_name = currentTransaction.category_name;
transactionRow.split = false;
transactionRow.split_index = 0;
transactionRow.split_parent = null;
// default values:
row.splits = [];
row.key = transaction.id;
row.id = transaction.id
row.dummy = false;
return transactionRow;
// pick this up from the first transaction
let first = transaction.attributes.transactions[0];
row.type = first.type;
row.date = new Date(first.date);
row.date_formatted = format(row.date, this.$t('config.month_and_day_fns'));
row.description = first.description;
row.collapsed = true;
row.split = false;
row.amount = 0;
row.currency_code = first.currency_code;
if (transaction.attributes.transactions.length > 1) {
row.split = true;
row.description = transaction.attributes.group_title;
}
// collapsed?
if (typeof transaction.collapsed !== 'undefined') {
row.collapsed = transaction.collapsed;
}
console.log('is collapsed? ' + row.collapsed);
// then loop each split
for (let i in transaction.attributes.transactions) {
if (transaction.attributes.transactions.hasOwnProperty(i)) {
let info = transaction.attributes.transactions[i];
let split = {};
row.amount = row.amount + parseFloat(info.amount);
split.description = info.description;
split.amount = info.amount;
split.currency_code = info.currency_code;
split.source_name = info.source_name;
split.source_id = info.source_id;
split.destination_name = info.destination_name;
split.destination_id = info.destination_id;
split.category_id = info.category_id;
split.category_name = info.category_name;
split.split_index = i;
row.splits.push(split);
}
}
return row;
},
toggleCollapse: function (id) {
let transaction = this.transactions.filter(transaction => transaction.id === id)[0];
transaction.collapsed = !transaction.collapsed;
},
// getTransactionRow(transaction, index) {
// let transactionRow = {};
// let currentTransaction = transaction.attributes.transactions[index];
//
// transactionRow.key = transaction.id;
// transactionRow.id = transaction.id;
// transactionRow.type = currentTransaction.type;
// transactionRow.description = currentTransaction.description;
// transactionRow.amount = currentTransaction.amount;
// transactionRow.currency_code = currentTransaction.currency_code;
// transactionRow.date = new Date(currentTransaction.date);
// transactionRow.date_formatted = format(transactionRow.date, this.$t('config.month_and_day_fns'));
// transactionRow.source_name = currentTransaction.source_name;
// transactionRow.source_id = currentTransaction.source_id;
// transactionRow.destination_name = currentTransaction.destination_name;
// transactionRow.destination_id = currentTransaction.destination_id;
// transactionRow.category_id = currentTransaction.category_id;
// transactionRow.category_name = currentTransaction.category_name;
// transactionRow.split = false;
// transactionRow.split_index = 0;
// transactionRow.split_parent = null;
//
// return transactionRow;
// },
tableSortCompare: function (aRow, bRow, key, sortDesc, formatter, compareOptions, compareLocale) {
let a = aRow[key]

View File

@ -1071,9 +1071,9 @@
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/node@*":
version "16.9.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708"
integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==
version "16.9.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.2.tgz#81f5a039d6ed1941f8cc57506c74e7c2b8fc64b9"
integrity sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w==
"@types/parse-json@^4.0.0":
version "4.0.0"
@ -2067,9 +2067,9 @@ codemirror@^5.60.0:
integrity sha512-zZAyOfN8TU67ngqrxhOgtkSAGV9jSpN1snbl8elPtnh9Z5A11daR405+dhLzLnuXrwX0WCShWlybxPN3QC/9Pg==
collect.js@^4.28.5:
version "4.28.6"
resolved "https://registry.yarnpkg.com/collect.js/-/collect.js-4.28.6.tgz#7fb75ae93b8198f7bb88461e263ea09744d0c56b"
integrity sha512-NAyuk1DnCotRaDZIS5kJ4sptgkwOeYqElird10yziN5JBuwYOGkOTguhNcPn5g344IfylZecxNYZAVXgv19p5Q==
version "4.29.0"
resolved "https://registry.yarnpkg.com/collect.js/-/collect.js-4.29.0.tgz#2fecc535b5e5712a5c7eeaa2c2d510f3113ec423"
integrity sha512-yhgGYEsLEcqnLT1NmRlN1+1euoz9SDhxQ4QyDhWYsKoWsg7252PKA5++dWaDs8mdFxbkmXDXQUaHXI9J2eTPkQ==
color-convert@^1.9.0, color-convert@^1.9.3:
version "1.9.3"
@ -2933,9 +2933,9 @@ ekko-lightbox@^5.3.0:
integrity sha512-mbacwySuVD3Ad6F2hTkjSTvJt59bcVv2l/TmBerp4xZnLak8tPtA4AScUn4DL42c1ksTiAO6sGhJZ52P/1Qgew==
electron-to-chromium@^1.3.830:
version "1.3.840"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.840.tgz#3f2a1df97015d9b1db5d86a4c6bd4cdb920adcbb"
integrity sha512-yRoUmTLDJnkIJx23xLY7GbSvnmDCq++NSuxHDQ0jiyDJ9YZBUGJcrdUqm+ZwZFzMbCciVzfem2N2AWiHJcWlbw==
version "1.3.842"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.842.tgz#641e414012dded277468892c0156cb01984f4f6f"
integrity sha512-P/nDMPIYdb2PyqCQwhTXNi5JFjX1AsDVR0y6FrHw752izJIAJ+Pn5lugqyBq4tXeRSZBMBb2ZGvRGB1djtELEQ==
elliptic@^6.5.3:
version "6.5.4"
@ -5671,9 +5671,9 @@ sass-loader@^12.0.0:
neo-async "^2.6.2"
sass@^1.39.2:
version "1.41.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.41.0.tgz#f7b41dc00336a4c03429c37b9680b86758af61d4"
integrity sha512-wb8nT60cjo9ZZMcHzG7TzdbFtCAmHEKWrH+zAdScPb4ZxL64WQBnGdbp5nwlenW5wJPcHva1JWmVa0h6iqA5eg==
version "1.41.1"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.41.1.tgz#bca5bed2154192779c29f48fca9c644c60c38d98"
integrity sha512-vIjX7izRxw3Wsiez7SX7D+j76v7tenfO18P59nonjr/nzCkZuoHuF7I/Fo0ZRZPKr88v29ivIdE9BqGDgQD/Nw==
dependencies:
chokidar ">=3.0.0 <4.0.0"
@ -6628,9 +6628,9 @@ webpack-sources@^3.2.0:
integrity sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==
webpack@^5.38.1, webpack@^5.52.1:
version "5.52.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.52.1.tgz#2dc1d9029ecb7acfb80da7bf67baab67baa517a7"
integrity sha512-wkGb0hLfrS7ML3n2xIKfUIwHbjB6gxwQHyLmVHoAqEQBw+nWo+G6LoHL098FEXqahqximsntjBLuewStrnJk0g==
version "5.53.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.53.0.tgz#f463cd9c6fc1356ae4b9b7ac911fd1f5b2df86af"
integrity sha512-RZ1Z3z3ni44snoWjfWeHFyzvd9HMVYDYC5VXmlYUT6NWgEOWdCNpad5Fve2CzzHoRED7WtsKe+FCyP5Vk4pWiQ==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long