mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Some code to get #384 working.
This commit is contained in:
parent
b93a96db23
commit
54c449f11b
@ -497,6 +497,20 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setOpposingAccounts(Collection $accounts): JournalCollectorInterface
|
||||||
|
{
|
||||||
|
$this->withOpposingAccount();
|
||||||
|
|
||||||
|
$this->query->whereIn('opposing.account_id', $accounts->pluck('id')->toArray());
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $page
|
* @param int $page
|
||||||
*
|
*
|
||||||
|
@ -85,6 +85,13 @@ interface JournalCollectorInterface
|
|||||||
*/
|
*/
|
||||||
public function removeFilter(string $filter): JournalCollectorInterface;
|
public function removeFilter(string $filter): JournalCollectorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setOpposingAccounts(Collection $accounts): JournalCollectorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
*
|
*
|
||||||
|
@ -24,10 +24,13 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Http\Controllers\Report;
|
namespace FireflyIII\Http\Controllers\Report;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
@ -56,23 +59,150 @@ class ExpenseController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function category(Collection $accounts, Collection $expense, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
// Properties for cache:
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('expense-category');
|
||||||
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
|
$cache->addProperty($expense->pluck('id')->toArray());
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
$combined = $this->combineAccounts($expense);
|
||||||
|
$all = new Collection;
|
||||||
|
foreach ($combined as $name => $combi) {
|
||||||
|
$all = $all->merge($combi);
|
||||||
|
}
|
||||||
|
// now find spent / earned:
|
||||||
|
$spent = $this->spentByCategory($accounts, $all, $start, $end);
|
||||||
|
$earned = $this->earnedByCategory($accounts, $combi, $start, $end);
|
||||||
|
|
||||||
|
// join arrays somehow:
|
||||||
|
$together = [];
|
||||||
|
foreach($spent as $categoryId => $spentInfo) {
|
||||||
|
if(!isset($together[$categoryId])) {
|
||||||
|
$together[$categoryId]['spent'] = $spentInfo;
|
||||||
|
// get category info:
|
||||||
|
$first = reset($spentInfo);
|
||||||
|
$together[$categoryId]['category'] = $first['category'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($earned as $categoryId => $earnedInfo) {
|
||||||
|
if(!isset($together[$categoryId])) {
|
||||||
|
$together[$categoryId]['earned'] = $earnedInfo;
|
||||||
|
// get category info:
|
||||||
|
$first = reset($earnedInfo);
|
||||||
|
$together[$categoryId]['category'] = $first['category'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = view('reports.partials.exp-categories', compact('together'))->render();
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Collection $expense
|
* @param Collection $expense
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array|mixed|string
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function spent(Collection $accounts, Collection $expense, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
// chart properties for cache:
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('expense-spent');
|
||||||
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
|
$cache->addProperty($expense->pluck('id')->toArray());
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
$combined = $this->combineAccounts($expense);
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($combined as $name => $combi) {
|
||||||
|
/**
|
||||||
|
* @var string $name
|
||||||
|
* @var Collection $combi
|
||||||
|
*/
|
||||||
|
$spent = $this->spentInPeriod($accounts, $combi, $start, $end);
|
||||||
|
$earned = $this->earnedInPeriod($accounts, $combi, $start, $end);
|
||||||
|
$result[$name] = [
|
||||||
|
'spent' => $spent,
|
||||||
|
'earned' => $earned,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$result = view('reports.partials.exp-not-grouped', compact('result'))->render();
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
// for period, get spent and earned for each account (by name)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $expense
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array|mixed|string
|
||||||
|
* @throws \Throwable
|
||||||
*/
|
*/
|
||||||
public function spentGrouped(Collection $accounts, Collection $expense, Carbon $start, Carbon $end)
|
public function spentGrouped(Collection $accounts, Collection $expense, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
$combined = $this->combineAccounts($expense);
|
// Properties for cache:
|
||||||
// for period, get spent and earned for each account (by name)
|
$cache = new CacheProperties;
|
||||||
/**
|
$cache->addProperty($start);
|
||||||
* @var string $name
|
$cache->addProperty($end);
|
||||||
* @var Collection $combi
|
$cache->addProperty('expense-spent-grouped');
|
||||||
*/
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
foreach($combined as $name => $combi) {
|
$cache->addProperty($expense->pluck('id')->toArray());
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$combined = $this->combineAccounts($expense);
|
||||||
|
$format = app('navigation')->preferredRangeFormat($start, $end);
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($combined as $name => $combi) {
|
||||||
|
$current = clone $start;
|
||||||
|
$combiSet = [];
|
||||||
|
while ($current <= $end) {
|
||||||
|
$period = $current->format('Ymd');
|
||||||
|
$periodName = app('navigation')->periodShow($current, $format);
|
||||||
|
$currentEnd = app('navigation')->endOfPeriod($current, $format);
|
||||||
|
/**
|
||||||
|
* @var string $name
|
||||||
|
* @var Collection $combi
|
||||||
|
*/
|
||||||
|
$spent = $this->spentInPeriod($accounts, $combi, $current, $currentEnd);
|
||||||
|
$earned = $this->earnedInPeriod($accounts, $combi, $current, $currentEnd);
|
||||||
|
$current = app('navigation')->addPeriod($current, $format, 0);
|
||||||
|
$combiSet[$period] = [
|
||||||
|
'period' => $periodName,
|
||||||
|
'spent' => $spent,
|
||||||
|
'earned' => $earned,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$result[$name] = $combiSet;
|
||||||
|
}
|
||||||
|
$result = view('reports.partials.exp-grouped', compact('result'))->render();
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function combineAccounts(Collection $accounts): array
|
protected function combineAccounts(Collection $accounts): array
|
||||||
@ -80,14 +210,187 @@ class ExpenseController extends Controller
|
|||||||
$combined = [];
|
$combined = [];
|
||||||
/** @var Account $expenseAccount */
|
/** @var Account $expenseAccount */
|
||||||
foreach ($accounts as $expenseAccount) {
|
foreach ($accounts as $expenseAccount) {
|
||||||
$combined[$expenseAccount->name] = [$expenseAccount];
|
$collection = new Collection;
|
||||||
|
$collection->push($expenseAccount);
|
||||||
|
|
||||||
$revenue = $this->accountRepository->findByName($expenseAccount->name, [AccountType::REVENUE]);
|
$revenue = $this->accountRepository->findByName($expenseAccount->name, [AccountType::REVENUE]);
|
||||||
if (!is_null($revenue->id)) {
|
if (!is_null($revenue->id)) {
|
||||||
$combined[$expenseAccount->name][] = $revenue;
|
$collection->push($revenue);
|
||||||
}
|
}
|
||||||
|
$combined[$expenseAccount->name] = $collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $combined;
|
return $combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function earnedInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
/** @var JournalCollectorInterface $collector */
|
||||||
|
$collector = app(JournalCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing);
|
||||||
|
$set = $collector->getJournals();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$currencyId])) {
|
||||||
|
$sum[$currencyId] = [
|
||||||
|
'sum' => '0',
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$currencyId]['sum'] = bcadd($sum[$currencyId]['sum'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function earnedByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
/** @var JournalCollectorInterface $collector */
|
||||||
|
$collector = app(JournalCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
|
||||||
|
$set = $collector->getJournals();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
$categoryName = $transaction->transaction_category_name;
|
||||||
|
$categoryId = intval($transaction->transaction_category_id);
|
||||||
|
// if null, grab from journal:
|
||||||
|
if ($categoryId === 0) {
|
||||||
|
$categoryName = $transaction->transaction_journal_category_name;
|
||||||
|
$categoryId = intval($transaction->transaction_journal_category_id);
|
||||||
|
}
|
||||||
|
if($categoryId !== 0) {
|
||||||
|
$categoryName = app('steam')->tryDecrypt($categoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$categoryId][$currencyId])) {
|
||||||
|
$sum[$categoryId][$currencyId] = [
|
||||||
|
'sum' => '0',
|
||||||
|
'category' => [
|
||||||
|
'id' => $categoryId,
|
||||||
|
'name' => $categoryName,
|
||||||
|
],
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$categoryId][$currencyId]['sum'] = bcadd($sum[$categoryId][$currencyId]['sum'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function spentByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
/** @var JournalCollectorInterface $collector */
|
||||||
|
$collector = app(JournalCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
|
||||||
|
$set = $collector->getJournals();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
$categoryName = $transaction->transaction_category_name;
|
||||||
|
$categoryId = intval($transaction->transaction_category_id);
|
||||||
|
// if null, grab from journal:
|
||||||
|
if ($categoryId === 0) {
|
||||||
|
$categoryName = $transaction->transaction_journal_category_name;
|
||||||
|
$categoryId = intval($transaction->transaction_journal_category_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$categoryId][$currencyId])) {
|
||||||
|
$sum[$categoryId][$currencyId] = [
|
||||||
|
'sum' => '0',
|
||||||
|
'category' => [
|
||||||
|
'id' => $categoryId,
|
||||||
|
'name' => $categoryName,
|
||||||
|
],
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$categoryId][$currencyId]['sum'] = bcadd($sum[$categoryId][$currencyId]['sum'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function spentInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
/** @var JournalCollectorInterface $collector */
|
||||||
|
$collector = app(JournalCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing);
|
||||||
|
$set = $collector->getJournals();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$currencyId])) {
|
||||||
|
$sum[$currencyId] = [
|
||||||
|
'sum' => '0',
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$currencyId]['sum'] = bcadd($sum[$currencyId]['sum'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
29
public/js/ff/reports/account/all.js
vendored
29
public/js/ff/reports/account/all.js
vendored
@ -25,4 +25,33 @@ function loadAjaxPartial(holder, uri) {
|
|||||||
}).fail(function () {
|
}).fail(function () {
|
||||||
failAjaxPartial(uri, holder);
|
failAjaxPartial(uri, holder);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function failAjaxPartial(uri, holder) {
|
||||||
|
"use strict";
|
||||||
|
var holderObject = $('#' + holder);
|
||||||
|
holderObject.parent().find('.overlay').remove();
|
||||||
|
holderObject.addClass('general-chart-error');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayAjaxPartial(data, holder) {
|
||||||
|
"use strict";
|
||||||
|
var obj = $('#' + holder);
|
||||||
|
obj.html(data);
|
||||||
|
obj.parent().find('.overlay').remove();
|
||||||
|
|
||||||
|
// call some often needed recalculations and what-not:
|
||||||
|
|
||||||
|
// find a sortable table and make it sortable:
|
||||||
|
if (typeof $.bootstrapSortable === "function") {
|
||||||
|
$.bootstrapSortable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the info click things and respond to them:
|
||||||
|
triggerInfoClick();
|
||||||
|
|
||||||
|
// trigger list thing
|
||||||
|
listLengthInitial();
|
||||||
|
|
||||||
}
|
}
|
36
resources/views/reports/partials/exp-categories.twig
Normal file
36
resources/views/reports/partials/exp-categories.twig
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<table class="table table-hover sortable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-defaultsign="az">{{ 'category'|_ }}</th>
|
||||||
|
<th style="text-align: right;">{{ 'spent'|_ }}</th>
|
||||||
|
<th style="text-align: right;">{{ 'earned'|_ }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for categoryId, entry in together %}
|
||||||
|
<tr>
|
||||||
|
<td data-value="{% if entry.category.name|length ==0 %}{{ 'noCategory'|_ }}{% else %}{{ entry.category.name }}{% endif %}">
|
||||||
|
<a href="{{ route('categories.show', categoryId) }}">{% if entry.category.name|length ==0 %}{{ 'noCategory'|_ }}{% else %}{{ entry.category.name }}{% endif %}</a>
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;">
|
||||||
|
{% if entry.spent|length ==0 %}
|
||||||
|
{{ '0'|formatAmount }}
|
||||||
|
{% else %}
|
||||||
|
{% for expense in entry.spent %}
|
||||||
|
{{ formatAmountBySymbol(expense.sum, expense.currency.symbol, expense.currency.dp) }}<br />
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td style="width:20px;">
|
||||||
|
{% if entry.earned|length ==0 %}
|
||||||
|
{{ '0'|formatAmount }}
|
||||||
|
{% else %}
|
||||||
|
{% for income in entry.earned %}
|
||||||
|
{{ formatAmountBySymbol(income.sum, income.currency.symbol, income.currency.dp) }}<br />
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
37
resources/views/reports/partials/exp-grouped.twig
Normal file
37
resources/views/reports/partials/exp-grouped.twig
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<table class="table table-hover sortable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-defaultsign="az">{{ 'name'|_ }}</th>
|
||||||
|
<th data-defaultsign="az">{{ 'period'|_ }}</th>
|
||||||
|
<th class="hidden-xs" style="text-align: right;" data-defaultsort="disabled">{{ 'spent'|_ }}</th>
|
||||||
|
<th class="hidden-xs" style="text-align: right;" data-defaultsort="disabled">{{ 'earned'|_ }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for name, periods in result %}
|
||||||
|
{% for periodIndex, period in periods %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ name }}</td>
|
||||||
|
<td data-value="{{ periodIndex }}">{{ period.period }}</td>
|
||||||
|
<td style="text-align: right;" >
|
||||||
|
{% if period.spent|length == 0%}
|
||||||
|
{{ '0'|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
{% for expense in period.spent %}
|
||||||
|
{{ formatAmountBySymbol(expense.sum, expense.currency.symbol, expense.currency.dp) }}<br />
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;" >
|
||||||
|
{% if period.earned|length == 0 %}
|
||||||
|
{{ '0'|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
{% for income in period.earned %}
|
||||||
|
{{ formatAmountBySymbol(income.sum, income.currency.symbol, income.currency.dp) }}<br />
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
33
resources/views/reports/partials/exp-not-grouped.twig
Normal file
33
resources/views/reports/partials/exp-not-grouped.twig
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<table class="table table-hover sortable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-defaultsign="az">{{ 'name'|_ }}</th>
|
||||||
|
<th class="hidden-xs" style="text-align: right;" data-defaultsort="disabled">{{ 'spent'|_ }}</th>
|
||||||
|
<th class="hidden-xs" style="text-align: right;" data-defaultsort="disabled">{{ 'earned'|_ }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for name, amounts in result %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ name }}</td>
|
||||||
|
<td style="text-align: right;" >
|
||||||
|
{% if amounts.spent|length == 0%}
|
||||||
|
{{ '0'|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
{% for expense in amounts.spent %}
|
||||||
|
{{ formatAmountBySymbol(expense.sum, expense.currency.symbol, expense.currency.dp) }}<br />
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;" >
|
||||||
|
{% if amounts.earned|length == 0 %}
|
||||||
|
{{ '0'|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
{% for income in amounts.earned %}
|
||||||
|
{{ formatAmountBySymbol(income.sum, income.currency.symbol, income.currency.dp) }}<br />
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
Loading…
Reference in New Issue
Block a user