From d1325ffbd80fae71c754cb3fd7026ee005dc0bf1 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 14 Mar 2020 19:12:32 +0100 Subject: [PATCH] New charts for #2726 --- .../Chart/Basic/GeneratorInterface.php | 4 +- .../Chart/TransactionController.php | 240 ++++++++++++++++++ public/v1/js/ff/transactions/index.js | 28 ++ resources/lang/en_US/firefly.php | 1 + resources/views/v1/transactions/index.twig | 59 +++++ routes/web.php | 15 ++ 6 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/Chart/TransactionController.php create mode 100644 public/v1/js/ff/transactions/index.js diff --git a/app/Generator/Chart/Basic/GeneratorInterface.php b/app/Generator/Chart/Basic/GeneratorInterface.php index 3bf8331f19..b92994f858 100644 --- a/app/Generator/Chart/Basic/GeneratorInterface.php +++ b/app/Generator/Chart/Basic/GeneratorInterface.php @@ -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'] * ] * ] * diff --git a/app/Http/Controllers/Chart/TransactionController.php b/app/Http/Controllers/Chart/TransactionController.php new file mode 100644 index 0000000000..6bea98b9dc --- /dev/null +++ b/app/Http/Controllers/Chart/TransactionController.php @@ -0,0 +1,240 @@ +. + */ + +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); + } + +} \ No newline at end of file diff --git a/public/v1/js/ff/transactions/index.js b/public/v1/js/ff/transactions/index.js new file mode 100644 index 0000000000..93749d5eb9 --- /dev/null +++ b/public/v1/js/ff/transactions/index.js @@ -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 . + */ + +$(function () { + "use strict"; + if (!showAll) { + multiCurrencyPieChart(categoryChartUri, 'category_chart'); + multiCurrencyPieChart(budgetChartUri, 'budget_chart'); + multiCurrencyPieChart(destinationChartUri, 'destination_chart'); + } +}); \ No newline at end of file diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 04553a8a45..97bfafa8ef 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -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', diff --git a/resources/views/v1/transactions/index.twig b/resources/views/v1/transactions/index.twig index 5a45763663..17b1db6d3e 100644 --- a/resources/views/v1/transactions/index.twig +++ b/resources/views/v1/transactions/index.twig @@ -15,6 +15,51 @@ {% 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 %} +
+ {# for withdrawals, deposits and transfers #} +
+
+
+

{{ 'categories'|_ }}

+
+
+ +
+
+
+ {# only for withdrawals #} + {% if objectType == 'withdrawal' %} +
+
+
+

{{ 'budgets'|_ }}

+
+
+ +
+
+
+ {% endif %} + {# for all #} +
+
+
+

{{ 'all_destination_accounts'|_ }}

+
+
+ +
+
+
+
+ {% endif %} + {# list with journals #}
@@ -68,4 +113,18 @@ {% block scripts %} {# required for groups.twig #} + + + + + + + {% endblock %} diff --git a/routes/web.php b/routes/web.php index e2b95b0769..7734d0abc9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -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 */