mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
New charts for #2726
This commit is contained in:
parent
bfc6a70c9f
commit
d1325ffbd8
app
public/v1/js/ff/transactions
resources
routes
@ -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']
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
|
240
app/Http/Controllers/Chart/TransactionController.php
Normal file
240
app/Http/Controllers/Chart/TransactionController.php
Normal 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
28
public/v1/js/ff/transactions/index.js
vendored
Normal 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');
|
||||
}
|
||||
});
|
@ -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',
|
||||
|
@ -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 %}
|
||||
|
@ -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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user