This commit is contained in:
James Cole 2016-12-15 14:38:05 +01:00
parent cdd988b4de
commit 975a6c34bf
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
4 changed files with 112 additions and 425 deletions

View File

@ -1,180 +0,0 @@
<?php
/**
* ChartJsReportChartGenerator.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Generator\Chart\Report;
use Illuminate\Support\Collection;
/**
* Class ChartJsReportChartGenerator
*
* @package FireflyIII\Generator\Chart\Report
*/
class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
{
/**
* Same as above but other translations.
*
* @param Collection $entries
*
* @return array
*/
public function multiYearOperations(Collection $entries): array
{
$data = [
'count' => 2,
'labels' => [],
'datasets' => [
[
'label' => trans('firefly.income'),
'data' => [],
],
[
'label' => trans('firefly.expenses'),
'data' => [],
],
],
];
foreach ($entries as $entry) {
$data['labels'][] = $entry[0]->formatLocalized('%Y');
$data['datasets'][0]['data'][] = round($entry[1], 2);
$data['datasets'][1]['data'][] = round($entry[2], 2);
}
return $data;
}
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function multiYearSum(string $income, string $expense, int $count): array
{
$data = [
'count' => 2,
'labels' => [trans('firefly.sum_of_years'), trans('firefly.average_of_years')],
'datasets' => [
[
'label' => trans('firefly.income'),
'data' => [],
],
[
'label' => trans('firefly.expenses'),
'data' => [],
],
],
];
$data['datasets'][0]['data'][] = round($income, 2);
$data['datasets'][1]['data'][] = round($expense, 2);
$data['datasets'][0]['data'][] = round(($income / $count), 2);
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
return $data;
}
/**
* @param Collection $entries
*
* @return array
*/
public function netWorth(Collection $entries): array
{
$format = (string)trans('config.month_and_day');
$data = [
'count' => 1,
'labels' => [],
'datasets' => [
[
'label' => trans('firefly.net_worth'),
'data' => [],
],
],
];
foreach ($entries as $entry) {
$data['labels'][] = trim($entry['date']->formatLocalized($format));
$data['datasets'][0]['data'][] = round($entry['net-worth'], 2);
}
return $data;
}
/**
* @param Collection $entries
*
* @return array
*/
public function yearOperations(Collection $entries): array
{
// language:
$format = (string)trans('config.month');
$data = [
'count' => 2,
'labels' => [],
'datasets' => [
[
'label' => trans('firefly.income'),
'data' => [],
],
[
'label' => trans('firefly.expenses'),
'data' => [],
],
],
];
foreach ($entries as $entry) {
$data['labels'][] = $entry[0]->formatLocalized($format);
$data['datasets'][0]['data'][] = round($entry[1], 2);
$data['datasets'][1]['data'][] = round($entry[2], 2);
}
return $data;
}
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function yearSum(string $income, string $expense, int $count): array
{
$data = [
'count' => 2,
'labels' => [trans('firefly.sum_of_year'), trans('firefly.average_of_year')],
'datasets' => [
[
'label' => trans('firefly.income'),
'data' => [],
],
[
'label' => trans('firefly.expenses'),
'data' => [],
],
],
];
$data['datasets'][0]['data'][] = round($income, 2);
$data['datasets'][1]['data'][] = round($expense, 2);
$data['datasets'][0]['data'][] = round(($income / $count), 2);
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
return $data;
}
}

View File

@ -1,65 +0,0 @@
<?php
/**
* ReportChartGeneratorInterface.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Generator\Chart\Report;
use Illuminate\Support\Collection;
/**
* Interface ReportChartGeneratorInterface
*
* @package FireflyIII\Generator\Chart\Report
*/
interface ReportChartGeneratorInterface
{
/**
* @param Collection $entries
*
* @return array
*/
public function multiYearOperations(Collection $entries): array;
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function multiYearSum(string $income, string $expense, int $count): array;
/**
* @param Collection $entries
*
* @return array
*/
public function netWorth(Collection $entries): array;
/**
* @param Collection $entries
*
* @return array
*/
public function yearOperations(Collection $entries): array;
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function yearSum(string $income, string $expense, int $count): array;
}

View File

@ -15,7 +15,7 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Chart\Report\ReportChartGeneratorInterface;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Support\CacheProperties;
@ -32,7 +32,7 @@ use Steam;
class ReportController extends Controller
{
/** @var ReportChartGeneratorInterface */
/** @var GeneratorInterface */
protected $generator;
/**
@ -42,7 +42,7 @@ class ReportController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = app(ReportChartGeneratorInterface::class);
$this->generator = app(GeneratorInterface::class);
}
/**
@ -59,30 +59,25 @@ class ReportController extends Controller
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty('netWorth');
$cache->addProperty('chart.report.net-worth');
$cache->addProperty($start);
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) {
return Response::json($cache->get());
}
$ids = $accounts->pluck('id')->toArray();
$current = clone $start;
$entries = new Collection;
$ids = $accounts->pluck('id')->toArray();
$current = clone $start;
$chartData = [];
while ($current < $end) {
$balances = Steam::balancesById($ids, $current);
$sum = $this->arraySum($balances);
$entries->push(
[
'date' => clone $current,
'net-worth' => $sum,
]
);
$balances = Steam::balancesById($ids, $current);
$sum = $this->arraySum($balances);
$label = $current->formatLocalized(strval(trans('config.month_and_day')));
$chartData[$label] = $sum;
$current->addDays(7);
}
$data = $this->generator->netWorth($entries);
$data = $this->generator->singleSet(strval(trans('firefly.net_worth')), $chartData);
$cache->store($data);
return Response::json($data);
@ -103,31 +98,47 @@ class ReportController extends Controller
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty('yearInOut');
$cache->addProperty('chart.report.operations');
$cache->addProperty($start);
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) {
return Response::json($cache->get());
}
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
$source = $this->getChartData($accounts, $start, $end);
$chartData = [
[
'label' => trans('firefly.income'),
'type' => 'bar',
'entries' => [],
],
[
'label' => trans('firefly.expenses'),
'type' => 'bar',
'entries' => [],
],
];
$chartSource = $this->getYearData($accounts, $start, $end);
if ($start->diffInMonths($end) > 12) {
// data = method X
$data = $this->multiYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end);
$cache->store($data);
return Response::json($data);
foreach ($source['earned'] as $date => $amount) {
$carbon = new Carbon($date);
$label = $carbon->formatLocalized($format);
$earned = $chartData[0]['entries'][$label] ?? '0';
$chartData[0]['entries'][$label] = bcadd($earned, $amount);
}
foreach ($source['spent'] as $date => $amount) {
$carbon = new Carbon($date);
$label = $carbon->formatLocalized($format);
$spent = $chartData[1]['entries'][$label] ?? '0';
$chartData[1]['entries'][$label] = bcadd($spent, $amount);
}
// data = method Y
$data = $this->singleYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end);
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return Response::json($data);
}
/**
@ -142,162 +153,67 @@ class ReportController extends Controller
public function sum(Collection $accounts, Carbon $start, Carbon $end)
{
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty('yearInOutSummarized');
$cache->addProperty('chart.report.sum');
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
if ($cache->has()) {
return Response::json($cache->get());
}
$chartSource = $this->getYearData($accounts, $start, $end);
if ($start->diffInMonths($end) > 12) {
// per year
$data = $this->multiYearSum($chartSource['earned'], $chartSource['spent'], $start, $end);
$cache->store($data);
return Response::json($data);
$source = $this->getChartData($accounts, $start, $end);
$numbers = [
'sum_earned' => '0',
'avg_earned' => '0',
'count_earned' => 0,
'sum_spent' => '0',
'avg_spent' => '0',
'count_spent' => 0,
];
foreach ($source['earned'] as $amount) {
$numbers['sum_earned'] = bcadd($amount, $numbers['sum_earned']);
$numbers['count_earned']++;
}
// per month!
$data = $this->singleYearSum($chartSource['earned'], $chartSource['spent'], $start, $end);
if ($numbers['count_earned'] > 0) {
$numbers['avg_earned'] = $numbers['sum_earned'] / $numbers['count_earned'];
}
foreach ($source['spent'] as $amount) {
$numbers['sum_spent'] = bcadd($amount, $numbers['sum_spent']);
$numbers['count_spent']++;
}
if ($numbers['count_spent'] > 0) {
$numbers['avg_spent'] = $numbers['sum_spent'] / $numbers['count_spent'];
}
$chartData = [
[
'label' => strval(trans('firefly.income')),
'type' => 'bar',
'entries' => [
strval(trans('firefly.sum_of_period')) => $numbers['sum_earned'],
strval(trans('firefly.average_in_period')) => $numbers['avg_earned'],
],
],
[
'label' => trans('firefly.expenses'),
'type' => 'bar',
'entries' => [
strval(trans('firefly.sum_of_period')) => $numbers['sum_spent'],
strval(trans('firefly.average_in_period')) => $numbers['avg_spent'],
],
],
];
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return Response::json($data);
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function multiYearOperations(array $earned, array $spent, Carbon $start, Carbon $end)
{
$entries = new Collection;
while ($start < $end) {
$incomeSum = $this->pluckFromArray($start->year, $earned);
$expenseSum = $this->pluckFromArray($start->year, $spent);
$entries->push([clone $start, $incomeSum, $expenseSum]);
$start->addYear();
}
$data = $this->generator->multiYearOperations($entries);
return $data;
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function multiYearSum(array $earned, array $spent, Carbon $start, Carbon $end)
{
$income = '0';
$expense = '0';
$count = 0;
while ($start < $end) {
$currentIncome = $this->pluckFromArray($start->year, $earned);
$currentExpense = $this->pluckFromArray($start->year, $spent);
$income = bcadd($income, $currentIncome);
$expense = bcadd($expense, $currentExpense);
$count++;
$start->addYear();
}
$data = $this->generator->multiYearSum($income, $expense, $count);
return $data;
}
/**
* @param int $year
* @param array $set
*
* @return string
*/
protected function pluckFromArray($year, array $set)
{
$sum = '0';
foreach ($set as $date => $amount) {
if (substr($date, 0, 4) == $year) {
$sum = bcadd($sum, $amount);
}
}
return $sum;
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function singleYearOperations(array $earned, array $spent, Carbon $start, Carbon $end)
{
// per month? simply use each month.
$entries = new Collection;
while ($start < $end) {
// total income and total expenses:
$date = $start->format('Y-m');
$incomeSum = isset($earned[$date]) ? $earned[$date] : 0;
$expenseSum = isset($spent[$date]) ? $spent[$date] : 0;
$entries->push([clone $start, $incomeSum, $expenseSum]);
$start->addMonth();
}
$data = $this->generator->yearOperations($entries);
return $data;
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function singleYearSum(array $earned, array $spent, Carbon $start, Carbon $end)
{
$income = '0';
$expense = '0';
$count = 0;
while ($start < $end) {
$date = $start->format('Y-m');
$currentIncome = isset($earned[$date]) ? $earned[$date] : 0;
$currentExpense = isset($spent[$date]) ? $spent[$date] : 0;
$income = bcadd($income, $currentIncome);
$expense = bcadd($expense, $currentExpense);
$count++;
$start->addMonth();
}
$data = $this->generator->yearSum($income, $expense, $count);
return $data;
}
/**
* @param $array
*
@ -314,31 +230,45 @@ class ReportController extends Controller
}
/**
* Collects the incomes and expenses for the given periods, grouped per month. Will cache its results
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function getYearData(Collection $accounts, Carbon $start, Carbon $end): array
private function getChartData(Collection $accounts, Carbon $start, Carbon $end): array
{
$cache = new CacheProperties;
$cache->addProperty('chart.report.get-chart-data');
$cache->addProperty($start);
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) {
return $cache->get();
}
$tasker = app(AccountTaskerInterface::class);
$currentStart = clone $start;
$spentArray = [];
$earnedArray = [];
while ($currentStart <= $end) {
$currentEnd = Navigation::endOfPeriod($currentStart, '1M');
$date = $currentStart->format('Y-m');
$spent = $tasker->amountOutInPeriod($accounts, $accounts, $currentStart, $currentEnd);
$earned = $tasker->amountInInPeriod($accounts, $accounts, $currentStart, $currentEnd);
$spentArray[$date] = bcmul($spent, '-1');
$earnedArray[$date] = $earned;
$currentStart = Navigation::addPeriod($currentStart, '1M', 0);
$currentEnd = Navigation::endOfPeriod($currentStart, '1M');
$label = $currentStart->format('Y-m') . '-01';
$spent = $tasker->amountOutInPeriod($accounts, $accounts, $currentStart, $currentEnd);
$earned = $tasker->amountInInPeriod($accounts, $accounts, $currentStart, $currentEnd);
$spentArray[$label] = bcmul($spent, '-1');
$earnedArray[$label] = $earned;
$currentStart = Navigation::addPeriod($currentStart, '1M', 0);
}
return [
$result = [
'spent' => $spentArray,
'earned' => $earnedArray,
];
$cache->store($result);
return $result;
}
}

View File

@ -719,6 +719,8 @@ return [
'average_income_per_account' => 'Average income per account',
'total' => 'Total',
'description' => 'Description',
'sum_of_period' => 'Sum of period',
'average_in_period' => 'Average in period',
// charts: