First working example of category report. No content, just place holders. #396

This commit is contained in:
James Cole 2016-11-10 06:23:21 +01:00
parent 8583b574ac
commit 5d4f1bc76d
15 changed files with 345 additions and 196 deletions

View File

@ -111,6 +111,15 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
}
/**
* @param Carbon $date
*

View File

@ -0,0 +1,99 @@
<?php
/**
* MonthReportGenerator.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\Report\Category;
use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use Illuminate\Support\Collection;
/**
* Class MonthReportGenerator
*
* @package FireflyIII\Generator\Report\Category
*/
class MonthReportGenerator implements ReportGeneratorInterface
{
/** @var Collection */
private $accounts;
/** @var Collection */
private $categories;
/** @var Carbon */
private $end;
/** @var Carbon */
private $start;
/**
* @return string
*/
public function generate(): string
{
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
$reportType = 'category';
// render!
return view('reports.category.month', compact('accountIds', 'reportType'))
->with('start', $this->start)->with('end', $this->end)
->with('categories', $this->categories)
->render();
}
/**
* @param Collection $accounts
*
* @return ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface
{
$this->accounts = $accounts;
return $this;
}
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
$this->categories = $categories;
return $this;
}
/**
* @param Carbon $date
*
* @return ReportGeneratorInterface
*/
public function setEndDate(Carbon $date): ReportGeneratorInterface
{
$this->end = $date;
return $this;
}
/**
* @param Carbon $date
*
* @return ReportGeneratorInterface
*/
public function setStartDate(Carbon $date): ReportGeneratorInterface
{
$this->start = $date;
return $this;
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* MultiYearReportGenerator.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\Report\Category;
/**
* Class MultiYearReportGenerator
*
* @package FireflyIII\Generator\Report\Audit
*/
class MultiYearReportGenerator extends MonthReportGenerator
{
/**
* Doesn't do anything different.
*/
}

View File

@ -0,0 +1,28 @@
<?php
/**
* YearReportGenerator.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\Report\Category;
/**
* Class YearReportGenerator
*
* @package FireflyIII\Generator\Report\Audit
*/
class YearReportGenerator extends MonthReportGenerator
{
/**
* Doesn't do anything different.
*/
}

View File

@ -55,6 +55,6 @@ class ReportGeneratorFactory
return $obj;
}
throw new FireflyException(sprintf('Class "%s" does not exist.', $class));
throw new FireflyException(sprintf('Cannot generate report. There is no "%s"-report for period "%s".', $type, $period));
}
}

View File

@ -36,6 +36,13 @@ interface ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface;
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface;
/**
* @param Carbon $date
*

View File

@ -87,4 +87,13 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
}
}

View File

@ -16,7 +16,6 @@ namespace FireflyIII\Generator\Report\Standard;
use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use Illuminate\Support\Collection;
/**
@ -61,6 +60,15 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
}
/**
* @param Carbon $date
*

View File

@ -16,7 +16,6 @@ namespace FireflyIII\Generator\Report\Standard;
use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use Illuminate\Support\Collection;
/**
@ -61,6 +60,15 @@ class YearReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
}
/**
* @param Carbon $date
*

View File

@ -23,15 +23,11 @@ use FireflyIII\Helpers\Collector\JournalCollector;
use FireflyIII\Helpers\FiscalHelperInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use stdClass;
@ -45,20 +41,16 @@ class ReportHelper implements ReportHelperInterface
/** @var BudgetRepositoryInterface */
protected $budgetRepository;
/** @var TagRepositoryInterface */
protected $tagRepository;
/**
* ReportHelper constructor.
*
*
* @param BudgetRepositoryInterface $budgetRepository
* @param TagRepositoryInterface $tagRepository
*/
public function __construct(BudgetRepositoryInterface $budgetRepository, TagRepositoryInterface $tagRepository)
public function __construct(BudgetRepositoryInterface $budgetRepository)
{
$this->budgetRepository = $budgetRepository;
$this->tagRepository = $tagRepository;
}
/**
@ -234,78 +226,4 @@ class ReportHelper implements ReportHelperInterface
return $months;
}
/**
* Returns an array of tags and their comparitive size with amounts bla bla.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
public function tagReport(Carbon $start, Carbon $end, Collection $accounts): array
{
$ids = $accounts->pluck('id')->toArray();
$set = Tag::
leftJoin('tag_transaction_journal', 'tags.id', '=', 'tag_transaction_journal.tag_id')
->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin(
'transactions AS source', function (JoinClause $join) {
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')->where('source.amount', '<', '0');
}
)
->leftJoin(
'transactions AS destination', function (JoinClause $join) {
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')->where('destination.amount', '>', '0');
}
)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where(
// source.account_id in accountIds XOR destination.account_id in accountIds
function (Builder $query) use ($ids) {
$query->where(
function (Builder $q1) use ($ids) {
$q1->whereIn('source.account_id', $ids)
->whereNotIn('destination.account_id', $ids);
}
)->orWhere(
function (Builder $q2) use ($ids) {
$q2->whereIn('destination.account_id', $ids)
->whereNotIn('source.account_id', $ids);
}
);
}
)
->get(['tags.id', 'tags.tag', 'transaction_journals.id as journal_id', 'destination.amount']);
$collection = [];
if ($set->count() === 0) {
return $collection;
}
/** @var Tag $entry */
foreach ($set as $entry) {
// less than zero? multiply to be above zero.
$amount = $entry->amount;
$id = intval($entry->id);
$previousAmount = $collection[$id]['amount'] ?? '0';
$collection[$id] = [
'id' => $id,
'tag' => $entry->tag,
'amount' => bcadd($previousAmount, $amount),
];
}
// cleanup collection (match "fonts")
$max = strval(max(array_column($collection, 'amount')));
foreach ($collection as $id => $entry) {
$size = bcdiv($entry['amount'], $max, 4);
if (bccomp($size, '0.25') === -1) {
$size = '0.5';
}
$collection[$id]['fontsize'] = $size;
}
return $collection;
}
}

View File

@ -80,15 +80,4 @@ interface ReportHelperInterface
*/
public function listOfMonths(Carbon $date): array;
/**
* Returns an array of tags and their comparitive size with amounts bla bla.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
*/
public function tagReport(Carbon $start, Carbon $end, Collection $accounts): array;
}

View File

@ -16,22 +16,15 @@ namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Generator\Report\ReportGeneratorFactory;
use FireflyIII\Generator\Report\Standard\MonthReportGenerator;
use FireflyIII\Generator\Report\StandardReportGenerator;
use FireflyIII\Helpers\Collector\JournalCollector;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Http\Requests\ReportFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Collection;
use Preferences;
use Response;
use Session;
use Steam;
use View;
/**
@ -56,6 +49,7 @@ class ReportController extends Controller
function ($request, $next) {
View::share('title', trans('firefly.reports'));
View::share('mainTitleIcon', 'fa-line-chart');
View::share('subTitleIcon', 'fa-calendar');
$this->helper = app(ReportHelperInterface::class);
@ -75,12 +69,9 @@ class ReportController extends Controller
*/
public function auditReport(Carbon $start, Carbon $end, Collection $accounts)
{
// throw an error if necessary.
if ($end < $start) {
throw new FireflyException('End date cannot be before start date, silly!');
return view('error')->with('message', trans('firefly.end_after_start_date'));
}
// lower threshold
if ($start < session('first')) {
$start = session('first');
}
@ -94,7 +85,7 @@ class ReportController extends Controller
]
)
);
View::share('subTitleIcon', 'fa-calendar');
$generator = ReportGeneratorFactory::reportGenerator('Audit', $start, $end);
$generator->setAccounts($accounts);
@ -112,14 +103,47 @@ class ReportController extends Controller
* @return string
* @throws FireflyException
*/
public function defaultReport(Carbon $start, Carbon $end, Collection $accounts)
public function categoryReport(Carbon $start, Carbon $end, Collection $accounts, Collection $categories)
{
// throw an error if necessary.
if ($end < $start) {
throw new FireflyException('End date cannot be before start date, silly!');
return view('error')->with('message', trans('firefly.end_after_start_date'));
}
if ($start < session('first')) {
$start = session('first');
}
// lower threshold
View::share(
'subTitle', trans(
'firefly.report_category',
[
'start' => $start->formatLocalized($this->monthFormat),
'end' => $end->formatLocalized($this->monthFormat),
]
)
);
$generator = ReportGeneratorFactory::reportGenerator('Category', $start, $end);
$generator->setAccounts($accounts);
$generator->setCategories($categories);
$result = $generator->generate();
return $result;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return string
* @throws FireflyException
*/
public function defaultReport(Carbon $start, Carbon $end, Collection $accounts)
{
if ($end < $start) {
return view('error')->with('message', trans('firefly.end_after_start_date'));
}
if ($start < session('first')) {
$start = session('first');
}
@ -133,7 +157,6 @@ class ReportController extends Controller
]
)
);
View::share('subTitleIcon', 'fa-calendar');
$generator = ReportGeneratorFactory::reportGenerator('Standard', $start, $end);
$generator->setAccounts($accounts);
@ -155,16 +178,8 @@ class ReportController extends Controller
$start = clone session('first');
$months = $this->helper->listOfMonths($start);
$customFiscalYear = Preferences::get('customFiscalYear', 0)->data;
// does the user have shared accounts?
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
// get id's for quick links:
$accountIds = [];
/** @var Account $account */
foreach ($accounts as $account) {
$accountIds [] = $account->id;
}
$accountList = join(',', $accountIds);
$accountList = join(',', $accounts->pluck('id')->toArray());
return view('reports.index', compact('months', 'accounts', 'start', 'accountList', 'customFiscalYear'));
@ -177,7 +192,6 @@ class ReportController extends Controller
*/
public function options(string $reportType)
{
$result = '';
switch ($reportType) {
default:
$result = $this->noReportOptions();
@ -206,7 +220,7 @@ class ReportController extends Controller
$categories = join(',', $request->getCategoryList()->pluck('id')->toArray());
if ($end < $start) {
throw new FireflyException('End date cannot be before start date, silly!');
return view('error')->with('message', trans('firefly.end_after_start_date'));
}
// lower threshold

View File

@ -686,6 +686,8 @@ return [
'reports_extra_options' => 'Extra options',
'report_has_no_extra_options' => 'This report has no extra options',
'reports_submit' => 'View report',
'end_after_start_date' => 'End date of report must be after start date.',
'select_category' => 'Select one or more categories.',
// charts:
'chart' => 'Chart',

View File

@ -0,0 +1,65 @@
{% extends "./layout/default" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-4">
Summary here. Accounts and categories involved. Summary of in/out
</div>
<div class="col-lg-4">
Pie chart with spending (aka all withdrawals in category). Optional checkbox to include all other transactions.
</div>
<div class="col-lg-4">
Pie chart with income (aka all deposits in category). Optional checkbox to include all other transactions (for comparison).
</div>
</div>
<div class="row">
<div class="col-lg-12">
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.
</div>
</div>
<div class="row">
<div class="col-lg-3">
List of spending (withdrawals) by account, if relevant. Grouped:<br>
BC: 456
AH: 123
order by size
linked to chart
use reset button to reset after chart was clicked.
</div>
<div class="col-lg-3">
List of spending (withdrawals) by transaction, if relevant. Not grouped<br>
more groceries: 456
groceries: 123
ordered by size. top x list?
</div>
<div class="col-lg-6">
Same but for income
</div>
</div>
{% endblock %}
{% block scripts %}
{% endblock %}
{% block styles %}
{% endblock %}

View File

@ -113,10 +113,13 @@
<h3 class="box-title">{{ 'quick_link_reports'|_ }}</h3>
</div>
<div class="box-body">
<h4>{{ 'quick_link_default_report'|_ }}</h4>
{% for type in ['default','audit'] %}
<h4>{{ ('quick_link_'~type~'_report')|_ }}</h4>
<ul>
<li>
<a href="{{ route('reports.report.default',
<a href="{{ route('reports.report.'~type,
[
'currentMonthStart',
'currentMonthEnd',
@ -124,7 +127,7 @@
]) }}">{{ 'report_this_month_quick'|_ }}</a>
</li>
<li>
<a href="{{ route('reports.report.default',
<a href="{{ route('reports.report.'~type,
[
'currentYearStart',
'currentYearEnd',
@ -133,7 +136,7 @@
</li>
{% if customFiscalYear == 1 %}
<li>
<a href="{{ route('reports.report.default',
<a href="{{ route('reports.report.'~type,
['default',
'currentFiscalYearStart',
'currentFiscalYearEnd',
@ -142,45 +145,7 @@
</li>
{% endif %}
<li>
<a href="{{ route('reports.report.default',
[
start.format('Ymd'),
'currentMonthEnd',
accountList
]) }}">{{ 'report_all_time_quick'|_ }}</a>
</li>
</ul>
<h4>{{ 'quick_link_audit_report'|_ }}</h4>
<ul>
<li>
<a href="{{ route('reports.report.audit',
[
'currentMonthStart',
'currentMonthEnd',
accountList
]) }}">{{ 'report_this_month_quick'|_ }}</a>
</li>
<li>
<a href="{{ route('reports.report.audit',
[
'currentYearStart',
'currentYearEnd',
accountList
]) }}">{{ 'report_this_year_quick'|_ }}</a>
</li>
{% if customFiscalYear == 1 %}
<li>
<a href="{{ route('reports.report.audit',
[
'currentFiscalYearStart',
'currentFiscalYearEnd',
accountList
]) }}">{{ 'report_this_fiscal_year_quick'|_ }}</a>
</li>
{% endif %}
<li>
<a href="{{ route('reports.report.audit',
<a href="{{ route('reports.report.'~type,
[
start.format('Ymd'),
'currentMonthEnd',
@ -188,6 +153,7 @@
]) }}">{{ 'report_all_time_quick'|_ }}</a>
</li>
</ul>
{% endfor %}
<p>
<em>{{ 'reports_can_bookmark'|_ }}</em>
</p>