Expand view of report and make multi currency

This commit is contained in:
James Cole 2019-09-01 15:23:33 +02:00
parent 1e9f354a81
commit ce06fb73b1
13 changed files with 124 additions and 147 deletions

View File

@ -81,6 +81,16 @@ class PopupReport implements PopupReportInterface
*/
public function balanceForNoBudget(Account $account, array $attributes): array
{
// filter by currency, if set.
$currencyId = $attributes['currencyId'] ?? null;
$currency = null;
if (null !== $currencyId) {
/** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class);
$currency = $repos->find((int)$currencyId);
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector
@ -91,6 +101,10 @@ class PopupReport implements PopupReportInterface
->setRange($attributes['startDate'], $attributes['endDate'])
->withoutBudget();
if (null !== $currency) {
$collector->setCurrency($currency);
}
return $collector->getExtractedJournals();
}
@ -139,12 +153,12 @@ class PopupReport implements PopupReportInterface
/**
* Collect journals by a category.
*
* @param Category $category
* @param Category|null $category
* @param array $attributes
*
* @return array
*/
public function byCategory(Category $category, array $attributes): array
public function byCategory(?Category $category, array $attributes): array
{
// filter by currency, if set.
$currencyId = $attributes['currencyId'] ?? null;
@ -163,8 +177,15 @@ class PopupReport implements PopupReportInterface
->withAccountInformation()
->withBudgetInformation()
->withCategoryInformation()
->setRange($attributes['startDate'], $attributes['endDate'])->withAccountInformation()
->setCategory($category);
->setRange($attributes['startDate'], $attributes['endDate'])->withAccountInformation();
if(null!== $category) {
$collector->setCategory($category);
}
if(null === $category) {
$collector->withoutCategory();
}
if (null !== $currency) {
$collector->setCurrency($currency);
}

View File

@ -32,6 +32,7 @@ use Illuminate\Support\Collection;
*/
interface PopupReportInterface
{
/**
* Get balances for budget.
*
@ -66,12 +67,12 @@ interface PopupReportInterface
/**
* Group by category.
*
* @param Category $category
* @param Category|null $category
* @param array $attributes
*
* @return array
*/
public function byCategory(Category $category, array $attributes): array;
public function byCategory(?Category $category, array $attributes): array;
/**
* Do something with expense. Sorry, I am not very inspirational here.

View File

@ -30,9 +30,6 @@ use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Http\Request;
use Log;
@ -46,14 +43,8 @@ class AvailableBudgetController extends Controller
/** @var AvailableBudgetRepositoryInterface */
private $abRepository;
/** @var BudgetLimitRepositoryInterface */
private $blRepository;
/** @var CurrencyRepositoryInterface */
private $currencyRepos;
/** @var OperationsRepositoryInterface */
private $opsRepository;
/** @var BudgetRepositoryInterface The budget repository */
private $repository;
/**
* AmountController constructor.
@ -68,10 +59,7 @@ class AvailableBudgetController extends Controller
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.budgets'));
app('view')->share('mainTitleIcon', 'fa-tasks');
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
return $next($request);
@ -83,6 +71,13 @@ class AvailableBudgetController extends Controller
* Create will always assume the user's default currency, if it's not set.
*
* This method will check if there is no AB, and refuse to continue if it exists.
*
* @param Request $request
* @param Carbon $start
* @param Carbon $end
* @param TransactionCurrency|null $currency
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
*/
public function create(Request $request, Carbon $start, Carbon $end, ?TransactionCurrency $currency = null)
{
@ -106,10 +101,16 @@ class AvailableBudgetController extends Controller
/**
* createAlternative will show a list of enabled currencies so the user can pick one.
*
* @param Request $request
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function createAlternative(Request $request, Carbon $start, Carbon $end)
{
$currencies = $this->currencyRepos->getEnabled();
$currencies = $this->currencyRepos->getEnabled();
$availableBudgets = $this->abRepository->get($start, $end);
// remove already budgeted currencies:
@ -121,12 +122,14 @@ class AvailableBudgetController extends Controller
return false;
}
}
return true;
}
);
$page = (int)($request->get('page') ?? 1);
$page = (int)($request->get('page') ?? 1);
return view('budgets.available-budgets.create-alternative', compact('start', 'end', 'page', 'currencies'));
}
@ -145,6 +148,8 @@ class AvailableBudgetController extends Controller
/**
* @param AvailableBudget $availableBudget
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function edit(AvailableBudget $availableBudget)
{
@ -153,6 +158,8 @@ class AvailableBudgetController extends Controller
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function store(Request $request)
{
@ -197,6 +204,8 @@ class AvailableBudgetController extends Controller
/**
* @param Request $request
* @param AvailableBudget $availableBudget
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(Request $request, AvailableBudget $availableBudget)
{

View File

@ -31,7 +31,6 @@ use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
@ -50,8 +49,6 @@ class BudgetLimitController extends Controller
{
use DateCalculation;
/** @var AvailableBudgetRepositoryInterface */
private $abRepository;
/** @var BudgetLimitRepositoryInterface */
private $blRepository;
/** @var CurrencyRepositoryInterface */
@ -73,7 +70,6 @@ class BudgetLimitController extends Controller
app('view')->share('mainTitleIcon', 'fa-tasks');
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);

View File

@ -68,6 +68,9 @@ class ReportController extends Controller
case 'category-entry':
$html = $this->categoryEntry($attributes);
break;
case 'budget-entry':
$html = $this->budgetEntry($attributes);
break;
}
return response()->json(['html' => $html]);

View File

@ -75,6 +75,38 @@ trait RenderPartialViews
return $result;
}
/**
* View for transactions in a budget for an account.
*
* @param array $attributes
*
* @return string
*/
protected function budgetEntry(array $attributes): string // generate view for report.
{
/** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class);
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budget = $budgetRepository->findNull((int)$attributes['budgetId']);
$accountRepos = app(AccountRepositoryInterface::class);
$account = $accountRepos->findNull((int)$attributes['accountId']);
$journals = $popupHelper->balanceForBudget($budget, $account, $attributes);
// @codeCoverageIgnoreStart
try {
$view = view('popup.report.balance-amount', compact('journals', 'budget','account'))->render();
} catch (Throwable $e) {
Log::error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.';
}
// @codeCoverageIgnoreEnd
return $view;
}
/**
* Get options for budget report.
@ -126,6 +158,7 @@ trait RenderPartialViews
Log::error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.';
}
// @codeCoverageIgnoreEnd
return $view;
@ -146,12 +179,7 @@ trait RenderPartialViews
/** @var CategoryRepositoryInterface $categoryRepository */
$categoryRepository = app(CategoryRepositoryInterface::class);
$category = $categoryRepository->findNull((int)$attributes['categoryId']);
if (null === $category) {
return 'This is an unknown category. Apologies.';
}
$journals = $popupHelper->byCategory($category, $attributes);
$journals = $popupHelper->byCategory($category, $attributes);
// @codeCoverageIgnoreStart
try {
$view = view('popup.report.category-entry', compact('journals', 'category'))->render();
@ -159,6 +187,7 @@ trait RenderPartialViews
Log::error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.';
}
// @codeCoverageIgnoreEnd
return $view;
@ -216,6 +245,7 @@ trait RenderPartialViews
Log::error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.';
}
// @codeCoverageIgnoreEnd
return $view;
@ -314,7 +344,7 @@ trait RenderPartialViews
/** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class);
$account = $accountRepository->findNull((int)$attributes['accountId']);
$account = $accountRepository->findNull((int)$attributes['accountId']);
if (null === $account) {
return 'This is an unknown category. Apologies.';
@ -328,6 +358,7 @@ trait RenderPartialViews
Log::error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.';
}
// @codeCoverageIgnoreEnd
return $view;

View File

@ -1,31 +0,0 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span><span class="sr-only">{{ 'close'|_ }}</span>
</button>
<h4 class="modal-title">
{{ trans('firefly.update_budget_amount_range',
{start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat)}) }}
</h4>
</div>
<form style="display: inline;" id="income" action="{{ route('budgets.income.post') }}" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>
<input type="hidden" name="end" value="{{ end.format('Y-m-d') }}"/>
<input type="hidden" name="page" value="{{ page }}" />
<div class="input-group">
<div class="input-group-addon">{{ defaultCurrency.symbol|raw }}</div>
<input step="any" class="form-control" id="amount" value="{{ available }}" autocomplete="off" name="amount" type="number"/>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
<button type="submit" class="btn btn-primary">{{ 'update_amount'|_ }}</button>
</div>
</form>
</div>
</div>

View File

@ -1,53 +0,0 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span><span class="sr-only">{{ 'close'|_ }}</span>
</button>
<h4 class="modal-title">
{{ trans('firefly.info_on_available_amount') }}
</h4>
</div>
<div class="modal-body">
<p>
{{ 'available_amount_indication'|_ }}
</p>
<table class="table table-bordered table-striped">
<tr>
<td>
{{ 'budgeted'|_ }}
<small><br/>
{{ trans('firefly.average_between', {start:searchBegin.formatLocalized(monthAndDayFormat), end:searchEnd.formatLocalized(monthAndDayFormat)}) }}
</td>
<td>
<span class="pull-right">{{ result.available|formatAmount }}</span>
</td>
</tr>
<tr>
<td>{{ 'earned'|_ }}
<small><br/>
{{ trans('firefly.average_between', {start:searchBegin.formatLocalized(monthAndDayFormat), end:searchEnd.formatLocalized(monthAndDayFormat)}) }}
</small>
</td>
<td><span class="pull-right">{{ result.earned|formatAmount }}</span></td>
</tr>
<tr>
<td>{{ 'spent'|_ }}
<small><br/>
{{ trans('firefly.average_between', {start:searchBegin.formatLocalized(monthAndDayFormat), end:searchEnd.formatLocalized(monthAndDayFormat)}) }}
</small>
</td>
<td><span class="pull-right">{{ result.spent|formatAmount }}</span></td>
</tr>
<tr>
<td><strong>{{ 'suggested'|_ }}</strong></td>
<td><span class="pull-right">{{ result.suggested|formatAmount }}</span></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
</div>
</div>
</div>

View File

@ -16,8 +16,6 @@
{{ trans('firefly.chart_all_journals_for_budget', {name:budget.name}) }}
{% endif %}
</h3>
<div class="box-tools pull-right">
<div class="btn-group">
<button class="btn btn-box-tool dropdown-toggle" data-toggle="dropdown"><i class="fa fa-ellipsis-v"></i></button>

View File

@ -4,7 +4,8 @@
<th>{{ 'budgets'|_ }}</th>
{% for account in report.accounts %}
{% if account.sum != 0 %}
<th class="hidden-xs" style="text-align: right;"><a href="{{ route('accounts.show',account.id) }}" title="{{ account.iban|default(account.name) }}">{{ account.name }}</a></th>
<th class="hidden-xs" style="text-align: right;"><a href="{{ route('accounts.show',account.id) }}"
title="{{ account.iban|default(account.name) }}">{{ account.name }}</a></th>
{% endif %}
{% endfor %}
<th style="text-align: right;">{{ 'sum'|_ }}</th>
@ -14,31 +15,34 @@
{% for budget in report.budgets %}
{% if budget.spent|length > 0 %}
<tr>
<td>
<a href="{{ route('budgets.show', [budget.budget_id]) }}">{{ budget.budget_name }}</a>
</td>
{% for account in report.accounts %}
{% if budget.spent[account.id] %}
<td style="text-align: right;">
{{ formatAmountBySymbol(budget.spent[account.id].spent, budget.spent[account.id].currency_symbol, budget.spent[account.id].currency_decimal_places) }}
<i class="fa fa-fw fa-info-circle text-muted"></i>
{# TODO #}
{#data-location="category-entry" data-category-id="{{ category.id }}" data-currency-id="{{ category.currency_id }}"-->#}
<tr>
<td>
<a href="{{ route('budgets.show', [budget.budget_id]) }}">{{ budget.budget_name }}</a>
</td>
{% else %}
{% if report.accounts[account.id].sum != 0 %}
<td>&nbsp;</td>
{% endif %}
{% endif %}
{% for account in report.accounts %}
{% if budget.spent[account.id] %}
<td style="text-align: right;">
{{ formatAmountBySymbol(budget.spent[account.id].spent, budget.spent[account.id].currency_symbol, budget.spent[account.id].currency_decimal_places) }}
<i data-location="budget-entry"
data-budget-id="{{ budget.budget_id }}"
data-account-id="{{ account.id }}"
data-currency-id="{{ budget.spent[account.id].currency_id }}"
class="fa fa-fw fa-info-circle text-muted firefly-info-button"></i>
</td>
{% else %}
{% if report.accounts[account.id].sum != 0 %}
<td>&nbsp;</td>
{% endif %}
{% endif %}
{% endfor %}
<td style="text-align: right;">
{% for sum in report.sums[budget.budget_id] %}
{{ formatAmountBySymbol(sum.sum, sum.currency_symbol, sum.currency_decimal_places) }} <i class="fa fa-fw fa-info-circle text-muted"></i><br />
{% endfor %}
</td>
</tr>
{% endfor %}
<td style="text-align: right;">
{% for sum in report.sums[budget.budget_id] %}
{{ formatAmountBySymbol(sum.sum, sum.currency_symbol, sum.currency_decimal_places) }} <i class="fa fa-fw fa-info-circle text-muted"></i>
<br/>
{% endfor %}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
@ -47,9 +51,9 @@
<td><em>{{ 'sum'|_ }}</em></td>
{% for account in report.accounts %}
{% if account.sum != 0 %}
<td style="text-align: right;">
<td style="text-align: right;">
{{ formatAmountBySymbol(account.sum, account.currency_symbol, account.currency_decimal_places) }}
</td>
</td>
{% endif %}
{% endfor %}
</tr>

View File

@ -29,7 +29,6 @@
{% else %}
<td data-value="0" style="text-align: right;">
{{ formatAmountBySymbol(0, info.currency_symbol, info.currency_decimal_places) }}
</td>
{% endif %}

View File

@ -22,8 +22,7 @@
<td style="text-align: right;">{{ formatAmountBySymbol(category.earned, category.currency_symbol, category.currency_decimal_places, true) }}</td>
<td style="text-align: right;">{{ formatAmountBySymbol(category.sum, category.currency_symbol, category.currency_decimal_places, true) }}</td>
<td style="width:20px;">
<i class="fa fa-fw fa-info-circle text-muted firefly-info-button"
data-location="category-entry" data-category-id="{{ category.id }}" data-currency-id="{{ category.currency_id }}"
<i class="fa fa-fw fa-info-circle text-muted firefly-info-button" data-location="category-entry" data-category-id="{{ category.id }}" data-currency-id="{{ category.currency_id }}"
></i>
</td>
</tr>

View File

@ -229,7 +229,7 @@ Route::group(
*/
Route::group(
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'available-budgets', 'as' => 'available-budgets.'],
static function () {s
static function () {
// create
Route::get('create/{start_date}/{end_date}/{currency?}', ['uses' => 'Budget\AvailableBudgetController@create', 'as' => 'create']);