New charts for

This commit is contained in:
James Cole 2020-03-14 19:12:32 +01:00
parent bfc6a70c9f
commit d1325ffbd8
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
6 changed files with 345 additions and 2 deletions
app
Generator/Chart/Basic
Http/Controllers/Chart
public/v1/js/ff/transactions
resources
lang/en_US
views/v1/transactions
routes

View File

@ -46,7 +46,7 @@ interface GeneratorInterface
* 'fill' => if to fill a line? optional, will not be included when unused.
* 'entries' =>
* [
* 'label-of-entry' => 'value'
* key => [value => x, 'currency_symbol' => 'x']
* ]
* ]
* 1: [
@ -56,7 +56,7 @@ interface GeneratorInterface
* 'fill' => if to fill a line? optional, will not be included when unused.
* 'entries' =>
* [
* 'label-of-entry' => 'value'
* key => [value => x, 'currency_symbol' => 'x']
* ]
* ]
*

View File

@ -0,0 +1,240 @@
<?php
/**
* TransactionController.php
* Copyright (c) 2020 thegrumpydictator@gmail.com
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
/**
* Class TransactionController
*/
class TransactionController extends Controller
{
/** @var GeneratorInterface Chart generation methods. */
protected $generator;
/**
* TransactionController constructor.
*/
public function __construct()
{
parent::__construct();
$this->generator = app(GeneratorInterface::class);
}
/**
* @param string $objectType
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
*/
public function budgets(Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('chart.transactions.budgets');
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end);
$collector->withBudgetInformation();
$collector->setTypes([TransactionType::WITHDRAWAL]);
$result = $collector->getExtractedJournals();
$data = [];
// group by category.
/** @var array $journal */
foreach ($result as $journal) {
$budget = $journal['budget_name'] ?? (string)trans('firefly.no_budget');
$title = sprintf('%s (%s)', $budget, $journal['currency_symbol']);
// key => [value => x, 'currency_symbol' => 'x']
$data[$title] = $data[$title] ?? [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $budget, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);
return response()->json($chart);
}
/**
* @param string $objectType
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
*/
public function categories(string $objectType, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($objectType);
$cache->addProperty('chart.transactions.categories');
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end);
$collector->withCategoryInformation();
switch ($objectType) {
default:
throw new FireflyException(sprintf('Cant handle "%s"', $objectType));
case 'withdrawal':
$collector->setTypes([TransactionType::WITHDRAWAL]);
break;
case 'deposit':
$collector->setTypes([TransactionType::DEPOSIT]);
break;
case 'transfers':
$collector->setTypes([TransactionType::TRANSFER]);
break;
}
$result = $collector->getExtractedJournals();
$data = [];
// group by category.
/** @var array $journal */
foreach ($result as $journal) {
$category = $journal['category_name'] ?? (string)trans('firefly.no_category');
$title = sprintf('%s (%s)', $category, $journal['currency_symbol']);
// key => [value => x, 'currency_symbol' => 'x']
$data[$title] = $data[$title] ?? [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $category, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);
return response()->json($chart);
}
/**
* @param string $objectType
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
*/
public function destinationAccounts(string $objectType, Carbon $start, Carbon $end)
{
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($objectType);
$cache->addProperty('chart.transactions.destinations');
if ($cache->has()) {
//return response()->json($cache->get()); // @codeCoverageIgnore
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end);
$collector->withAccountInformation();
switch ($objectType) {
default:
throw new FireflyException(sprintf('Cant handle "%s"', $objectType));
case 'withdrawal':
$collector->setTypes([TransactionType::WITHDRAWAL]);
break;
case 'deposit':
$collector->setTypes([TransactionType::DEPOSIT]);
break;
case 'transfers':
$collector->setTypes([TransactionType::TRANSFER]);
break;
}
$result = $collector->getExtractedJournals();
$data = [];
// group by category.
/** @var array $journal */
foreach ($result as $journal) {
$name = $journal['destination_account_name'];
$title = sprintf('%s (%s)', $name, $journal['currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['amount']);
if (null !== $journal['foreign_amount']) {
$title = sprintf('%s (%s)', $name, $journal['foreign_currency_symbol']);
$data[$title] = $data[$title] ?? [
'amount' => $journal['foreign_amount'],
'currency_symbol' => $journal['currency_symbol'],
];
$data[$title]['amount'] = bcadd($data[$title]['amount'], $journal['foreign_amount']);
}
}
$chart = $this->generator->multiCurrencyPieChart($data);
$cache->store($chart);
return response()->json($chart);
}
}

28
public/v1/js/ff/transactions/index.js vendored Normal file
View File

@ -0,0 +1,28 @@
/*
* show.js
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
$(function () {
"use strict";
if (!showAll) {
multiCurrencyPieChart(categoryChartUri, 'category_chart');
multiCurrencyPieChart(budgetChartUri, 'budget_chart');
multiCurrencyPieChart(destinationChartUri, 'destination_chart');
}
});

View File

@ -218,6 +218,7 @@ return [
'unpaid_in_currency' => 'Unpaid in :currency',
'is_alpha_warning' => 'You are running an ALPHA version. Be wary of bugs and issues.',
'is_beta_warning' => 'You are running an BETA version. Be wary of bugs and issues.',
'all_destination_accounts' => 'Destination accounts',
// check for updates:
'update_check_title' => 'Check for updates',

View File

@ -15,6 +15,51 @@
</div>
{% endif %}
{% if periods|length > 0 %}
{% set boxSize = 'col-lg-6 col-md-6 col-sm-12 col-xs-12' %}
{% if objectType == 'withdrawal' %}
{% set boxSize = 'col-lg-4 col-md-6 col-sm-12 col-xs-12' %}
{% endif %}
<div class="row">
{# for withdrawals, deposits and transfers #}
<div class="{{ boxSize }}">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'categories'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="category_chart" style="width:100%;height:250px;" height="250"></canvas>
</div>
</div>
</div>
{# only for withdrawals #}
{% if objectType == 'withdrawal' %}
<div class="{{ boxSize }}">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'budgets'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="budget_chart" style="width:100%;height:250px;" height="250"></canvas>
</div>
</div>
</div>
{% endif %}
{# for all #}
<div class="{{ boxSize }}">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'all_destination_accounts'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="destination_chart" style="width:100%;height:250px;" height="250"></canvas>
</div>
</div>
</div>
</div>
{% endif %}
{# list with journals #}
<div class="row">
<div class="{% if periods|length > 0 %}col-lg-10 col-md-10 col-sm-12{% else %}col-lg-12 col-md-12 col-sm-12{% endif %}">
@ -68,4 +113,18 @@
{% block scripts %}
{# required for groups.twig #}
<script type="text/javascript" src="v1/js/ff/list/groups.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" nonce="{{ JS_NONCE }}">
var showAll = {% if periods|length > 0 %}false{% else %}true{% endif %};
var categoryChartUri = '{{ route('chart.transactions.categories', [objectType, start.format('Y-m-d'), end.format('Y-m-d')]) }}';
var budgetChartUri = '{{ route('chart.transactions.budgets', [start.format('Y-m-d'), end.format('Y-m-d')]) }}';
var destinationChartUri = '{{ route('chart.transactions.destinationAccounts', [objectType, start.format('Y-m-d'), end.format('Y-m-d')]) }}';
</script>
<script type="text/javascript" src="v1/js/lib/Chart.bundle.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/lib/chartjs-plugin-annotation.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/ff/charts.defaults.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/ff/charts.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
<script type="text/javascript" src="v1/js/ff/transactions/index.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
{% endblock %}

View File

@ -488,6 +488,21 @@ Route::group(
}
);
/**
* Chart\Transactions Controller
*/
Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Chart', 'prefix' => 'chart/transactions', 'as' => 'chart.transactions.'],
static function () {
Route::get('categories/{objectType}/{start_date}/{end_date}', ['uses' => 'TransactionController@categories', 'as' => 'categories']);
Route::get('budgets/{start_date}/{end_date}', ['uses' => 'TransactionController@budgets', 'as' => 'budgets']);
Route::get('destinationAccounts/{objectType}/{start_date}/{end_date}', ['uses' => 'TransactionController@destinationAccounts', 'as' => 'destinationAccounts']);
//
}
);
/**
* Export controller
*/