mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-01-01 11:47:14 -06:00
Building report from issue #386
This commit is contained in:
parent
57e49c225b
commit
8377a2a0de
@ -60,6 +60,8 @@ class JournalCollector implements JournalCollectorInterface
|
||||
'account_types.type as account_type',
|
||||
];
|
||||
/** @var bool */
|
||||
private $filterInternalTransfers;
|
||||
/** @var bool */
|
||||
private $filterTransfers = false;
|
||||
/** @var bool */
|
||||
private $joinedBudget = false;
|
||||
@ -127,6 +129,26 @@ class JournalCollector implements JournalCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function disableInternalFilter(): JournalCollectorInterface
|
||||
{
|
||||
$this->filterInternalTransfers = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function enableInternalFilter(): JournalCollectorInterface
|
||||
{
|
||||
$this->filterInternalTransfers = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@ -138,6 +160,11 @@ class JournalCollector implements JournalCollectorInterface
|
||||
$set = $this->filterTransfers($set);
|
||||
Log::debug(sprintf('Count of set after filterTransfers() is %d', $set->count()));
|
||||
|
||||
// possibly filter "internal" transfers:
|
||||
$set = $this->filterInternalTransfers($set);
|
||||
Log::debug(sprintf('Count of set after filterInternalTransfers() is %d', $set->count()));
|
||||
|
||||
|
||||
// loop for decryption.
|
||||
$set->each(
|
||||
function (Transaction $transaction) {
|
||||
@ -501,6 +528,47 @@ class JournalCollector implements JournalCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function filterInternalTransfers(Collection $set): Collection
|
||||
{
|
||||
if ($this->filterInternalTransfers === false) {
|
||||
Log::debug('Did NO filtering for internal transfers on given set.');
|
||||
|
||||
return $set;
|
||||
}
|
||||
if ($this->joinedOpposing === false) {
|
||||
Log::error('Cannot filter internal transfers because no opposing information is present.');
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
$accountIds = $this->accountIds;
|
||||
$set = $set->filter(
|
||||
function (Transaction $transaction) use ($accountIds) {
|
||||
// both id's in $accountids?
|
||||
if (in_array($transaction->account_id, $accountIds) && in_array($transaction->opposing_account_id, $accountIds)) {
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Transaction #%d has #%d and #%d in set, so removed',
|
||||
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
|
||||
), $accountIds
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the set of accounts used by the collector includes more than one asset
|
||||
* account, chances are the set include double entries: transfers get selected
|
||||
@ -583,6 +651,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
private function joinOpposingTables()
|
||||
{
|
||||
if (!$this->joinedOpposing) {
|
||||
Log::debug('joinedOpposing is false');
|
||||
// join opposing transaction (hard):
|
||||
$this->query->leftJoin(
|
||||
'transactions as opposing', function (JoinClause $join) {
|
||||
@ -595,11 +664,12 @@ class JournalCollector implements JournalCollectorInterface
|
||||
$this->query->leftJoin('account_types as opposing_account_types', 'opposing_accounts.account_type_id', '=', 'opposing_account_types.id');
|
||||
$this->query->whereNull('opposing.deleted_at');
|
||||
|
||||
$this->fields[] = 'opposing.account_id as opposing_account_id';
|
||||
$this->fields[] = 'opposing_accounts.name as opposing_account_name';
|
||||
$this->fields[] = 'opposing_accounts.encrypted as opposing_account_encrypted';
|
||||
$this->fields[] = 'opposing_account_types.type as opposing_account_type';
|
||||
|
||||
$this->fields[] = 'opposing.account_id as opposing_account_id';
|
||||
$this->fields[] = 'opposing_accounts.name as opposing_account_name';
|
||||
$this->fields[] = 'opposing_accounts.encrypted as opposing_account_encrypted';
|
||||
$this->fields[] = 'opposing_account_types.type as opposing_account_type';
|
||||
$this->joinedOpposing = true;
|
||||
Log::debug('joinedOpposing is now true!');
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,17 +692,17 @@ class JournalCollector implements JournalCollectorInterface
|
||||
{
|
||||
|
||||
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC');
|
||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC');
|
||||
|
||||
return $query;
|
||||
|
||||
|
@ -38,6 +38,16 @@ interface JournalCollectorInterface
|
||||
*/
|
||||
public function disableFilter(): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function disableInternalFilter(): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return JournalCollectorInterface
|
||||
*/
|
||||
public function enableInternalFilter(): JournalCollectorInterface;
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@ -46,7 +56,7 @@ interface JournalCollectorInterface
|
||||
/**
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function getPaginatedJournals():LengthAwarePaginator;
|
||||
public function getPaginatedJournals(): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
|
@ -15,10 +15,15 @@ namespace FireflyIII\Http\Controllers\Report;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
|
||||
/**
|
||||
* Class CategoryController
|
||||
@ -27,6 +32,84 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function categoryPeriodReport(Carbon $start, Carbon $end, Collection $accounts)
|
||||
{
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
$categories = $repository->getCategories();
|
||||
$data = [];
|
||||
|
||||
// income only:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts($accounts)->setRange($start, $end)
|
||||
->withOpposingAccount()
|
||||
->enableInternalFilter()
|
||||
->setCategories($categories);
|
||||
|
||||
$transactions = $collector->getJournals();
|
||||
|
||||
// this is the date format we need:
|
||||
// define period to group on:
|
||||
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
|
||||
|
||||
// this is the set of transactions for this period
|
||||
// in these budgets. Now they must be grouped (manually)
|
||||
// id, period => amount
|
||||
$income = [];
|
||||
foreach ($transactions as $transaction) {
|
||||
$categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id));
|
||||
$date = $transaction->date->format($carbonFormat);
|
||||
|
||||
if (!isset($income[$categoryId])) {
|
||||
$income[$categoryId]['name'] = $this->getCategoryName($categoryId, $categories);
|
||||
$income[$categoryId]['sum'] = '0';
|
||||
$income[$categoryId]['entries'] = [];
|
||||
}
|
||||
|
||||
if (!isset($income[$categoryId]['entries'][$date])) {
|
||||
$income[$categoryId]['entries'][$date] = '0';
|
||||
}
|
||||
$income[$categoryId]['entries'][$date] = bcadd($income[$categoryId]['entries'][$date], $transaction->transaction_amount);
|
||||
}
|
||||
|
||||
// and now the same for stuff without a category:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end);
|
||||
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
|
||||
$collector->withoutCategory();
|
||||
$transactions = $collector->getJournals();
|
||||
|
||||
$income[0]['entries'] = [];
|
||||
$income[0]['name'] = strval(trans('firefly.no_category'));
|
||||
$income[0]['sum'] = '0';
|
||||
|
||||
foreach ($transactions as $transaction) {
|
||||
$date = $transaction->date->format($carbonFormat);
|
||||
|
||||
if (!isset($income[0]['entries'][$date])) {
|
||||
$income[0]['entries'][$date] = '0';
|
||||
}
|
||||
$income[0]['entries'][$date] = bcadd($income[0]['entries'][$date], $transaction->transaction_amount);
|
||||
}
|
||||
|
||||
$periods = Navigation::listOfPeriods($start, $end);
|
||||
|
||||
$income = $this->filterCategoryPeriodReport($income);
|
||||
|
||||
$result = view('reports.partials.category-period', compact('categories', 'periods', 'income'))->render();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportHelperInterface $helper
|
||||
@ -56,4 +139,52 @@ class CategoryController extends Controller
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters empty results from category period report
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function filterCategoryPeriodReport(array $data): array
|
||||
{
|
||||
/**
|
||||
* @var int $categoryId
|
||||
* @var array $set
|
||||
*/
|
||||
foreach ($data as $categoryId => $set) {
|
||||
$sum = '0';
|
||||
foreach ($set['entries'] as $amount) {
|
||||
$sum = bcadd($amount, $sum);
|
||||
}
|
||||
$data[$categoryId]['sum'] = $sum;
|
||||
if (bccomp('0', $sum) === 0) {
|
||||
unset($data[$categoryId]);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $categoryId
|
||||
* @param Collection $categories
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getCategoryName(int $categoryId, Collection $categories): string
|
||||
{
|
||||
|
||||
$first = $categories->filter(
|
||||
function (Category $category) use ($categoryId) {
|
||||
return $categoryId === $category->id;
|
||||
}
|
||||
);
|
||||
if (!is_null($first->first())) {
|
||||
return $first->first()->name;
|
||||
}
|
||||
|
||||
return '(unknown)';
|
||||
}
|
||||
|
||||
}
|
@ -226,55 +226,34 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
*/
|
||||
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
|
||||
$data = [];
|
||||
// prep data array:
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
$data[$budget->id] = [
|
||||
'name' => $budget->name,
|
||||
'sum' => '0',
|
||||
'entries' => [],
|
||||
];
|
||||
}
|
||||
|
||||
// get all transactions:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end);
|
||||
$collector->setAccounts($accounts)->setRange($start, $end);
|
||||
$collector->setBudgets($budgets);
|
||||
$transactions = $collector->getJournals();
|
||||
|
||||
// this is the date format we need:
|
||||
// define period to group on:
|
||||
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
|
||||
|
||||
// this is the set of transactions for this period
|
||||
// in these budgets. Now they must be grouped (manually)
|
||||
// id, period => amount
|
||||
$data = [];
|
||||
// loop transactions:
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$budgetId = max(intval($transaction->transaction_journal_budget_id), intval($transaction->transaction_budget_id));
|
||||
$date = $transaction->date->format($carbonFormat);
|
||||
|
||||
if (!isset($data[$budgetId])) {
|
||||
$data[$budgetId]['name'] = $this->getBudgetName($budgetId, $budgets);
|
||||
$data[$budgetId]['sum'] = '0';
|
||||
$data[$budgetId]['entries'] = [];
|
||||
}
|
||||
|
||||
if (!isset($data[$budgetId]['entries'][$date])) {
|
||||
$data[$budgetId]['entries'][$date] = '0';
|
||||
}
|
||||
$data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date], $transaction->transaction_amount);
|
||||
$budgetId = max(intval($transaction->transaction_journal_budget_id), intval($transaction->transaction_budget_id));
|
||||
$date = $transaction->date->format($carbonFormat);
|
||||
$data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date] ?? '0', $transaction->transaction_amount);
|
||||
}
|
||||
// and now the same for stuff without a budget:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end);
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL]);
|
||||
$collector->withoutBudget();
|
||||
$transactions = $collector->getJournals();
|
||||
|
||||
$data[0]['entries'] = [];
|
||||
$data[0]['name'] = strval(trans('firefly.no_budget'));
|
||||
$data[0]['sum'] = '0';
|
||||
|
||||
foreach ($transactions as $transaction) {
|
||||
$date = $transaction->date->format($carbonFormat);
|
||||
|
||||
if (!isset($data[0]['entries'][$date])) {
|
||||
$data[0]['entries'][$date] = '0';
|
||||
}
|
||||
$data[0]['entries'][$date] = bcadd($data[0]['entries'][$date], $transaction->transaction_amount);
|
||||
}
|
||||
$data[0] = $this->getNoBudgetPeriodReport($start, $end);
|
||||
|
||||
return $data;
|
||||
|
||||
@ -332,19 +311,23 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
Log::debug('spentInPeriod: and these accounts: ', $accountIds);
|
||||
Log::debug(sprintf('spentInPeriod: Start date is "%s", end date is "%s"', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
|
||||
$fromJournalsQuery = TransactionJournal::leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('transaction_types.type', 'Withdrawal');
|
||||
$fromJournalsQuery = TransactionJournal::leftJoin(
|
||||
'budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
|
||||
'transactions.amount', '<', 0
|
||||
);
|
||||
}
|
||||
)
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('transaction_types.type', 'Withdrawal');
|
||||
|
||||
// add budgets:
|
||||
if ($budgets->count() > 0) {
|
||||
@ -368,15 +351,15 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
* and transactions.account_id in (2)
|
||||
*/
|
||||
$fromTransactionsQuery = Transaction::leftJoin('budget_transaction', 'budget_transaction.transaction_id', '=', 'transactions.id')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->where('transactions.amount', '<', 0)
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('transaction_types.type', 'Withdrawal');
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->where('transactions.amount', '<', 0)
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('transaction_types.type', 'Withdrawal');
|
||||
|
||||
// add budgets:
|
||||
if ($budgets->count() > 0) {
|
||||
@ -569,4 +552,37 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
|
||||
return '(unknown)';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getNoBudgetPeriodReport(Carbon $start, Carbon $end): array
|
||||
{
|
||||
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAllAssetAccounts()->setRange($start, $end);
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL]);
|
||||
$collector->withoutBudget();
|
||||
$transactions = $collector->getJournals();
|
||||
$result = [
|
||||
'entries' => [],
|
||||
'name' => strval(trans('firefly.no_budget')),
|
||||
'sum' => '0',
|
||||
];
|
||||
|
||||
foreach ($transactions as $transaction) {
|
||||
$date = $transaction->date->format($carbonFormat);
|
||||
|
||||
if (!isset($result['entries'][$date])) {
|
||||
$result['entries'][$date] = '0';
|
||||
}
|
||||
$result['entries'][$date] = bcadd($result['entries'][$date], $transaction->transaction_amount);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -246,8 +246,8 @@ class Navigation
|
||||
* If the date difference between start and end is less than a month, method returns "Y-m-d". If the difference is less than a year,
|
||||
* method returns "Y-m". If the date difference is larger, method returns "Y".
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param \Carbon\Carbon $start
|
||||
* @param \Carbon\Carbon $end
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@ -270,8 +270,8 @@ class Navigation
|
||||
* If the date difference between start and end is less than a month, method returns "1D". If the difference is less than a year,
|
||||
* method returns "1M". If the date difference is larger, method returns "1Y".
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param \Carbon\Carbon $start
|
||||
* @param \Carbon\Carbon $end
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@ var fixHelper = function (e, tr) {
|
||||
|
||||
$(function () {
|
||||
"use strict";
|
||||
lineChart('chart/account/' + accountID, 'overview-chart');
|
||||
lineChart('chart/account/' + accountID, 'overview-chart');
|
||||
pieChart(incomeByCategoryUri, 'account-cat-in');
|
||||
pieChart(expenseByCategoryUri, 'account-cat-out');
|
||||
pieChart(expenseByBudgetUri, 'account-budget-out');
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* globals google, accountIds, budgetPeriodReportUri */
|
||||
/* globals google, accountIds, budgetPeriodReportUri, categoryPeriodReportUri */
|
||||
|
||||
$(function () {
|
||||
"use strict";
|
||||
drawChart();
|
||||
|
||||
loadAjaxPartial('budgetPeriodReport', budgetPeriodReportUri);
|
||||
loadAjaxPartial('categoryPeriodReport', categoryPeriodReportUri);
|
||||
});
|
||||
|
||||
function drawChart() {
|
||||
|
@ -113,6 +113,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# same thing but for categories #}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'categories'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding table-responsive loading" id="categoryPeriodReport">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="js/lib/bootstrap-sortable.js"></script>
|
||||
@ -135,6 +148,7 @@
|
||||
var incExpReportUri = '{{ route('reports.data.incExpReport', [start.format('Ymd'), end.format('Ymd'), accountIds]) }}';
|
||||
|
||||
var budgetPeriodReportUri = '{{ route('reports.data.budgetPeriodReport', [start.format('Ymd'), end.format('Ymd'), accountIds]) }}';
|
||||
var categoryPeriodReportUri = '{{ route('reports.data.categoryPeriodReport', [start.format('Ymd'), end.format('Ymd'), accountIds]) }}';
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="js/ff/reports/default/all.js"></script>
|
||||
|
54
resources/views/reports/partials/category-period.twig
Normal file
54
resources/views/reports/partials/category-period.twig
Normal file
@ -0,0 +1,54 @@
|
||||
<table class="table table-hover sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" data-defaultsort="disabled">{{ 'category'|_ }}</th>
|
||||
{% for period in periods %}
|
||||
<th colspan="2" data-defaultsort="disabled">{{ period }}</th>
|
||||
{% endfor %}
|
||||
<th colspan="2" data-defaultsort="disabled">{{ 'sum'|_ }}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
{% for period in periods %}
|
||||
<th data-defaultsign="_19">In</th>
|
||||
<th data-defaultsign="_19">Out</th>
|
||||
{% endfor %}
|
||||
<th data-defaultsign="_19">In</th>
|
||||
<th data-defaultsign="_19">Out</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in categories %}
|
||||
{% if income[category.id] %}
|
||||
<tr>
|
||||
<td data-value="{{ category.name }}">
|
||||
<a title="{{ category.name }}" href="#" data-category="{{ category.id }}" class="category-chart-activate">{{ category.name }}</a>
|
||||
</td>
|
||||
|
||||
{% for key, period in periods %}
|
||||
{# income first #}
|
||||
{% if(income[category.id].entries[key]) %}
|
||||
<td data-value="{{ income[category.id].entries[key] }}">
|
||||
{{ income[category.id].entries[key]|formatAmount }}
|
||||
</td>
|
||||
{% else %}
|
||||
<td data-value="0">
|
||||
{{ 0|formatAmount }}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
{# expenses #}
|
||||
<td data-value="0">
|
||||
<!-- expense -->
|
||||
</td>
|
||||
{% endfor %}
|
||||
<td data-value="{{ info.sum }}">
|
||||
0
|
||||
</td>
|
||||
<td data-value="{{ info.sum }}">
|
||||
1
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
@ -402,12 +402,19 @@ Route::group(
|
||||
'/reports/data/budget-report/{start_date}/{end_date}/{accountList}',
|
||||
['uses' => 'Report\BudgetController@budgetReport', 'as' => 'reports.data.budgetReport']
|
||||
);
|
||||
|
||||
// budget period overview
|
||||
Route::get(
|
||||
'/reports/data/budget-period/{start_date}/{end_date}/{accountList}',
|
||||
['uses' => 'Report\BudgetController@budgetPeriodReport', 'as' => 'reports.data.budgetPeriodReport']
|
||||
);
|
||||
|
||||
// category period overview
|
||||
Route::get(
|
||||
'/reports/data/category-period/{start_date}/{end_date}/{accountList}',
|
||||
['uses' => 'Report\CategoryController@categoryPeriodReport', 'as' => 'reports.data.categoryPeriodReport']
|
||||
);
|
||||
|
||||
/**
|
||||
* Rules Controller
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user