diff --git a/app/Generator/Report/Category/MonthReportGenerator.php b/app/Generator/Report/Category/MonthReportGenerator.php
index 8d2b535e67..3e0a82ef8c 100644
--- a/app/Generator/Report/Category/MonthReportGenerator.php
+++ b/app/Generator/Report/Category/MonthReportGenerator.php
@@ -63,10 +63,18 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
$accountSummary = $this->getAccountSummary();
$categorySummary = $this->getCategorySummary();
$averageExpenses = $this->getAverageExpenses();
+ $averageIncome = $this->getAverageIncome();
+ $topExpenses = $this->getTopExpenses();
+ $topIncome = $this->getTopIncome();
// render!
- return view('reports.category.month', compact('accountIds', 'categoryIds', 'reportType', 'accountSummary', 'categorySummary','averageExpenses'))
+ return view(
+ 'reports.category.month',
+ compact(
+ 'accountIds', 'categoryIds', 'topIncome', 'reportType', 'accountSummary', 'categorySummary', 'averageExpenses', 'averageIncome', 'topExpenses'
+ )
+ )
->with('start', $this->start)->with('end', $this->end)
->with('categories', $this->categories)
->with('accounts', $this->accounts)
@@ -203,6 +211,45 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
}
+ private function getAverageIncome(): array
+ {
+ $expenses = $this->getIncome();
+ $result = [];
+ /** @var Transaction $transaction */
+ foreach ($expenses as $transaction) {
+ // opposing name and ID:
+ $opposingId = $transaction->opposing_account_id;
+
+ // is not set?
+ if (!isset($result[$opposingId])) {
+ $name = $transaction->opposing_account_name;
+ $encrypted = intval($transaction->opposing_account_encrypted);
+ $name = $encrypted === 1 ? Crypt::decrypt($name) : $name;
+ $result[$opposingId] = [
+ 'name' => $name,
+ 'count' => 1,
+ 'id' => $opposingId,
+ 'average' => $transaction->transaction_amount,
+ 'sum' => $transaction->transaction_amount,
+ ];
+ continue;
+ }
+ $result[$opposingId]['count']++;
+ $result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
+ $result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
+ }
+
+ // sort result by average:
+ $average = [];
+ foreach ($result as $key => $row) {
+ $average[$key] = floatval($row['average']);
+ }
+
+ array_multisort($average, SORT_DESC, $result);
+
+ return $result;
+ }
+
/**
* @return array
*/
@@ -360,4 +407,40 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
}
+
+ /**
+ * @return Collection
+ */
+ private function getTopExpenses(): Collection
+ {
+ $transactions = $this->getExpenses()->sortBy('transaction_amount');
+
+ $transactions = $transactions->each(
+ function (Transaction $transaction) {
+ if (intval($transaction->opposing_account_encrypted) === 1) {
+ $transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
+ }
+ }
+ );
+
+ return $transactions;
+ }
+
+ /**
+ * @return Collection
+ */
+ private function getTopIncome(): Collection
+ {
+ $transactions = $this->getIncome()->sortByDesc('transaction_amount');
+
+ $transactions = $transactions->each(
+ function (Transaction $transaction) {
+ if (intval($transaction->opposing_account_encrypted) === 1) {
+ $transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
+ }
+ }
+ );
+
+ return $transactions;
+ }
}
\ No newline at end of file
diff --git a/public/js/ff/charts.js b/public/js/ff/charts.js
index 98d1ad463e..ad0576fa1a 100644
--- a/public/js/ff/charts.js
+++ b/public/js/ff/charts.js
@@ -66,57 +66,6 @@ function colorizeData(data) {
return newData;
}
-/**
- * @param URI
- * @param container
- * @param chartType
- * @param options
- * @param colorData
- */
-function drawAChart(URI, container, chartType, options, colorData) {
- if ($('#' + container).length === 0) {
- console.log('No container called ' + container + ' was found.');
- return;
- }
-
- // var result = true;
- // if (options.beforeDraw) {
- // result = options.beforeDraw(data, {url: URL, container: container});
- // }
- // if (result === false) {
- // return;
- // }
-
- $.getJSON(URI).done(function (data) {
-
- if (colorData) {
- data = colorizeData(data);
- }
-
- if (allCharts.hasOwnProperty(container)) {
- console.log('Will draw updated ' + chartType + ' chart');
- allCharts[container].data.datasets = data.datasets;
- allCharts[container].data.labels = data.labels;
- allCharts[container].update();
- } else {
- // new chart!
- console.log('Will draw new ' + chartType + 'chart');
- var ctx = document.getElementById(container).getContext("2d");
- allCharts[container] = new Chart(ctx, {
- type: chartType,
- data: data,
- options: options
- });
- }
-
- }).fail(function () {
- console.log('Failed to draw ' + chartType + ' in container ' + container);
- $('#' + container).addClass('general-chart-error');
- });
- console.log('URL for ' + chartType + ' chart : ' + URL);
-}
-
-
/**
* Function to draw a line chart:
* @param URI
@@ -182,3 +131,60 @@ function pieChart(URI, container) {
drawAChart(URI, container, chartType, options, colorData);
}
+
+
+/**
+ * @param URI
+ * @param container
+ * @param chartType
+ * @param options
+ * @param colorData
+ */
+function drawAChart(URI, container, chartType, options, colorData) {
+ if ($('#' + container).length === 0) {
+ console.log('No container called ' + container + ' was found.');
+ return;
+ }
+
+
+ $.getJSON(URI).done(function (data) {
+
+
+ if (data.labels.length === 0) {
+ console.log(chartType + " chart in " + container + " has no data.");
+ // remove the chart container + parent
+ var holder = $('#' + container).parent().parent();
+ if (holder.hasClass('box')) {
+ // remove box
+ holder.remove();
+ }
+ return;
+ }
+
+
+ if (colorData) {
+ data = colorizeData(data);
+ }
+
+ if (allCharts.hasOwnProperty(container)) {
+ console.log('Will draw updated ' + chartType + ' chart');
+ allCharts[container].data.datasets = data.datasets;
+ allCharts[container].data.labels = data.labels;
+ allCharts[container].update();
+ } else {
+ // new chart!
+ console.log('Will draw new ' + chartType + 'chart');
+ var ctx = document.getElementById(container).getContext("2d");
+ allCharts[container] = new Chart(ctx, {
+ type: chartType,
+ data: data,
+ options: options
+ });
+ }
+
+ }).fail(function () {
+ console.log('Failed to draw ' + chartType + ' in container ' + container);
+ $('#' + container).addClass('general-chart-error');
+ });
+ console.log('URL for ' + chartType + ' chart : ' + URL);
+}
diff --git a/public/js/ff/firefly.js b/public/js/ff/firefly.js
index d63eddbcc3..e57052381a 100644
--- a/public/js/ff/firefly.js
+++ b/public/js/ff/firefly.js
@@ -55,6 +55,10 @@ $(function () {
}
);
+
+ // trigger list thing
+ listLengthInitial();
+
});
function currencySelect(e) {
@@ -108,3 +112,30 @@ accounting.settings = {
decimal: "."
}
};
+
+
+function listLengthInitial() {
+ "use strict";
+ $('.overListLength').hide();
+ $('.listLengthTrigger').unbind('click').click(triggerList)
+}
+
+function triggerList(e) {
+ "use strict";
+ var link = $(e.target);
+ var table = link.parent().parent().parent().parent();
+ console.log('data-hidden = ' + table.attr('data-hidden'));
+ if (table.attr('data-hidden') === 'no') {
+ // hide all elements, return false.
+ table.find('.overListLength').hide();
+ table.attr('data-hidden', 'yes');
+ link.text(showFullList);
+ return false;
+ }
+ // show all, return false
+ table.find('.overListLength').show();
+ table.attr('data-hidden', 'no');
+ link.text(showOnlyTop);
+
+ return false;
+}
\ No newline at end of file
diff --git a/public/js/ff/index.js b/public/js/ff/index.js
index 3621132011..f03c97445f 100644
--- a/public/js/ff/index.js
+++ b/public/js/ff/index.js
@@ -43,29 +43,6 @@ function drawChart() {
getBoxAmounts();
}
-// /**
-// * Removes a chart box if there is nothing for the chart to draw.
-// *
-// * @param data
-// * @param options
-// * @returns {boolean}
-// */
-// function beforeDrawIsEmpty(data, options) {
-// "use strict";
-//
-// // check if chart holds data.
-// if (data.labels.length === 0) {
-// // remove the chart container + parent
-// console.log(options.container + ' appears empty. Removed.');
-// $('#' + options.container).parent().parent().remove();
-//
-// // return false so script stops.
-// return false;
-// }
-// return true;
-// }
-
-
function getBoxAmounts() {
"use strict";
var boxes = ['in', 'out', 'bills-unpaid', 'bills-paid'];
diff --git a/public/js/ff/reports/default/all.js b/public/js/ff/reports/default/all.js
index 3b47c14cf9..ec3fb8c1e6 100644
--- a/public/js/ff/reports/default/all.js
+++ b/public/js/ff/reports/default/all.js
@@ -27,32 +27,6 @@ function triggerInfoClick() {
$('.firefly-info-button').unbind('click').click(clickInfoButton);
}
-function listLengthInitial() {
- "use strict";
- $('.overListLength').hide();
- $('.listLengthTrigger').unbind('click').click(triggerList)
-}
-
-function triggerList(e) {
- "use strict";
- var link = $(e.target);
- var table = link.parent().parent().parent().parent();
- console.log('data-hidden = ' + table.attr('data-hidden'));
- if (table.attr('data-hidden') === 'no') {
- // hide all elements, return false.
- table.find('.overListLength').hide();
- table.attr('data-hidden', 'yes');
- link.text(showFullList);
- return false;
- }
- // show all, return false
- table.find('.overListLength').show();
- table.attr('data-hidden', 'no');
- link.text(showOnlyTop);
-
- return false;
-}
-
function clickInfoButton(e) {
"use strict";
// find all data tags, regardless of what they are:
diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php
index a57a2b43ff..db1eaa3010 100644
--- a/resources/lang/en_US/firefly.php
+++ b/resources/lang/en_US/firefly.php
@@ -698,8 +698,10 @@ return [
'everything_else' => 'Everything else',
'income_and_expenses' => 'Income and expenses',
'spent_average' => 'Spent (average)',
+ 'income_average' => 'Income (average)',
'transaction_count' => 'Transaction count',
-
+ 'average_spending_per_account' => 'Average spending per account',
+ 'average_income_per_account' => 'Average income per account',
// charts:
'chart' => 'Chart',
'dayOfMonth' => 'Day of the month',
diff --git a/resources/views/reports/category/month.twig b/resources/views/reports/category/month.twig
index 2048b765b3..7e860d70c5 100644
--- a/resources/views/reports/category/month.twig
+++ b/resources/views/reports/category/month.twig
@@ -16,31 +16,27 @@
- {{ 'name'|_ }}
- {{ 'earned'|_ }}
- {{ 'spent'|_ }}
+ {{ 'name'|_ }}
+ {{ 'earned'|_ }}
+ {{ 'spent'|_ }}
{% for account in accounts %}
-
+
{{ account.name }}
-
- {% if accountSummary[account.id] %}
- {{ accountSummary[account.id].earned|formatAmount }}
- {% else %}
- {{ 0|formatAmount }}
- {% endif %}
-
-
- {% if accountSummary[account.id] %}
- {{ accountSummary[account.id].spent|formatAmount }}
- {% else %}
- {{ 0|formatAmount }}
- {% endif %}
-
+ {% if accountSummary[account.id] %}
+ {{ accountSummary[account.id].earned|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
+ {% if accountSummary[account.id] %}
+ {{ accountSummary[account.id].spent|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
{% endfor %}
@@ -56,31 +52,27 @@
- {{ 'name'|_ }}
- {{ 'earned'|_ }}
- {{ 'spent'|_ }}
+ {{ 'name'|_ }}
+ {{ 'earned'|_ }}
+ {{ 'spent'|_ }}
{% for category in categories %}
-
+
{{ category.name }}
-
- {% if categorySummary[category.id] %}
- {{ categorySummary[category.id].earned|formatAmount }}
- {% else %}
- {{ 0|formatAmount }}
- {% endif %}
-
-
- {% if categorySummary[category.id] %}
- {{ categorySummary[category.id].spent|formatAmount }}
- {% else %}
- {{ 0|formatAmount }}
- {% endif %}
-
+ {% if categorySummary[category.id] %}
+ {{ categorySummary[category.id].earned|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
+ {% if categorySummary[category.id] %}
+ {{ categorySummary[category.id].spent|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
{% endfor %}
@@ -162,12 +154,6 @@
- {#
- big chart here
- Show income / expenses per period. Differs per report: month = per day, year = per month, multi-year = per year.
- In a bar chart, possibly grouped by expense/revenue account.
- #}
-
@@ -178,9 +164,10 @@
- {{ 'account'|_ }}
- {{ 'spent_average'|_ }}
- {{ 'transaction_count'|_ }}
+ {{ 'account'|_ }}
+ {{ 'spent_average'|_ }}
+ {{ 'total'|_ }}
+ {{ 'transaction_count'|_ }}
@@ -189,10 +176,13 @@
{{ row.name }}
-
+
{{ row.average|formatAmount }}
-
+
+ {{ row.sum|formatAmount }}
+
+
{{ row.count }}
@@ -203,69 +193,175 @@
-
-
-
-
-
+ {% if averageIncome|length > 0 %}
+
+
+
+
+
+
+
+ {{ 'account'|_ }}
+ {{ 'income_average'|_ }}
+ {{ 'total'|_ }}
+ {{ 'transaction_count'|_ }}
+
+
+
+ {% for row in averageIncome %}
+
+
+ {{ row.name }}
+
+
+ {{ row.average|formatAmount }}
+
+
+ {{ row.sum|formatAmount }}
+
+
+ {{ row.count }}
+
+
+ {% endfor %}
+
+
+
-
+ {% endif %}
-
-
-
- List of spending (withdrawals) by account, if relevant. Grouped:
-
- BC: 456
- AH: 123
-
- order by size
-
-
-
- List of spending (withdrawals) by transaction, if relevant. Not grouped
-
- more groceries: 456
- groceries: 123
-
- ordered by size. top x list?
-
-
-
- Same but for income
-
-
-
-
{% endblock %}
{% block scripts %}
+
@@ -284,4 +378,5 @@
{% endblock %}
{% block styles %}
+
{% endblock %}
\ No newline at end of file
diff --git a/resources/views/reports/partials/categories.twig b/resources/views/reports/partials/categories.twig
index a09cbe2c7c..281fd6ca5f 100644
--- a/resources/views/reports/partials/categories.twig
+++ b/resources/views/reports/partials/categories.twig
@@ -25,7 +25,7 @@
{% endfor %}
- {% if categories.getCategories.count > expenseTopLength %}
+ {% if categories.getCategories.count > listLength %}
{{ trans('firefly.show_full_list',{number:incomeTopLength}) }}
diff --git a/resources/views/reports/partials/expenses.twig b/resources/views/reports/partials/expenses.twig
index 3491b33564..f3cf12e4aa 100644
--- a/resources/views/reports/partials/expenses.twig
+++ b/resources/views/reports/partials/expenses.twig
@@ -24,7 +24,7 @@
{% endfor %}
- {% if expenses.getExpenses|length > expenseTopLength %}
+ {% if expenses.getExpenses|length > listLength %}
{{ trans('firefly.show_full_list',{number:incomeTopLength}) }}