mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Some extended code for the category report.
This commit is contained in:
parent
32b5a84a0c
commit
6d60d64a82
@ -23,6 +23,13 @@ use Illuminate\Support\Collection;
|
|||||||
interface CategoryChartGeneratorInterface
|
interface CategoryChartGeneratorInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function pieChart(array $data): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $entries
|
* @param Collection $entries
|
||||||
*
|
*
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
namespace FireflyIII\Generator\Chart\Category;
|
namespace FireflyIII\Generator\Chart\Category;
|
||||||
|
|
||||||
|
use FireflyIII\Support\ChartColour;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
@ -117,6 +118,30 @@ class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function pieChart(array $entries): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'datasets' => [
|
||||||
|
0 => [],
|
||||||
|
],
|
||||||
|
'labels' => [],
|
||||||
|
];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['datasets'][0]['data'][] = round($entry['amount'], 2);
|
||||||
|
$data['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
|
||||||
|
$data['labels'][] = $entry['name'];
|
||||||
|
$index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param Collection $entries
|
* @param Collection $entries
|
||||||
|
@ -16,7 +16,11 @@ namespace FireflyIII\Generator\Report\Category;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class MonthReportGenerator
|
* Class MonthReportGenerator
|
||||||
@ -40,12 +44,16 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
public function generate(): string
|
public function generate(): string
|
||||||
{
|
{
|
||||||
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
|
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
|
||||||
|
$categoryIds = join(',', $this->categories->pluck('id')->toArray());
|
||||||
$reportType = 'category';
|
$reportType = 'category';
|
||||||
|
$accountSummary = $this->getAccountSummary();
|
||||||
|
$categorySummary = $this->getCategorySummary();
|
||||||
|
|
||||||
// render!
|
// render!
|
||||||
return view('reports.category.month', compact('accountIds', 'reportType'))
|
return view('reports.category.month', compact('accountIds', 'categoryIds', 'reportType', 'accountSummary', 'categorySummary'))
|
||||||
->with('start', $this->start)->with('end', $this->end)
|
->with('start', $this->start)->with('end', $this->end)
|
||||||
->with('categories', $this->categories)
|
->with('categories', $this->categories)
|
||||||
|
->with('accounts', $this->accounts)
|
||||||
->render();
|
->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,4 +104,226 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getAccountSummary(): array
|
||||||
|
{
|
||||||
|
$spent = $this->getSpentAccountSummary();
|
||||||
|
$earned = $this->getEarnedAccountSummary();
|
||||||
|
$return = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $accountId
|
||||||
|
* @var string $entry
|
||||||
|
*/
|
||||||
|
foreach ($spent as $accountId => $entry) {
|
||||||
|
if (!isset($return[$accountId])) {
|
||||||
|
$return[$accountId] = ['spent' => 0, 'earned' => 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$return[$accountId]['spent'] = $entry;
|
||||||
|
}
|
||||||
|
unset($entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $accountId
|
||||||
|
* @var string $entry
|
||||||
|
*/
|
||||||
|
foreach ($earned as $accountId => $entry) {
|
||||||
|
if (!isset($return[$accountId])) {
|
||||||
|
$return[$accountId] = ['spent' => 0, 'earned' => 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$return[$accountId]['earned'] = $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getCategorySummary(): array
|
||||||
|
{
|
||||||
|
$spent = $this->getSpentCategorySummary();
|
||||||
|
$earned = $this->getEarnedCategorySummary();
|
||||||
|
$return = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $categoryId
|
||||||
|
* @var string $entry
|
||||||
|
*/
|
||||||
|
foreach ($spent as $categoryId => $entry) {
|
||||||
|
if (!isset($return[$categoryId])) {
|
||||||
|
$return[$categoryId] = ['spent' => 0, 'earned' => 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$return[$categoryId]['spent'] = $entry;
|
||||||
|
}
|
||||||
|
unset($entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $categoryId
|
||||||
|
* @var string $entry
|
||||||
|
*/
|
||||||
|
foreach ($earned as $categoryId => $entry) {
|
||||||
|
if (!isset($return[$categoryId])) {
|
||||||
|
$return[$categoryId] = ['spent' => 0, 'earned' => 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$return[$categoryId]['earned'] = $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getEarnedAccountSummary(): array
|
||||||
|
{
|
||||||
|
$transactions = $this->getIncomes();
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
$accountId = $transaction->account_id;
|
||||||
|
$result[$accountId] = $result[$accountId] ?? '0';
|
||||||
|
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getEarnedCategorySummary(): array
|
||||||
|
{
|
||||||
|
$transactions = $this->getIncomes();
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
||||||
|
$transCatId = intval($transaction->transaction_category_id);
|
||||||
|
$categoryId = max($jrnlCatId, $transCatId);
|
||||||
|
|
||||||
|
$result[$categoryId] = $result[$categoryId] ?? '0';
|
||||||
|
$result[$categoryId] = bcadd($transaction->transaction_amount, $result[$categoryId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getExpenses(): Collection
|
||||||
|
{
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||||
|
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||||
|
->setCategories($this->categories)->getOpposingAccount()->disableFilter();
|
||||||
|
|
||||||
|
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||||
|
$transactions = $collector->getJournals();
|
||||||
|
|
||||||
|
$transactions = $transactions->filter(
|
||||||
|
function (Transaction $transaction) use ($accountIds) {
|
||||||
|
$opposing = $transaction->opposing_account_id;
|
||||||
|
// remove internal transfer
|
||||||
|
if (in_array($opposing, $accountIds)) {
|
||||||
|
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// remove positive amount
|
||||||
|
if (bccomp($transaction->transaction_amount, '0') === 1) {
|
||||||
|
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transaction;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getIncomes(): Collection
|
||||||
|
{
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||||
|
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
||||||
|
->setCategories($this->categories)->getOpposingAccount();
|
||||||
|
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||||
|
$transactions = $collector->getJournals();
|
||||||
|
$transactions = $transactions->filter(
|
||||||
|
function (Transaction $transaction) use ($accountIds) {
|
||||||
|
$opposing = $transaction->opposing_account_id;
|
||||||
|
// remove internal transfer
|
||||||
|
if (in_array($opposing, $accountIds)) {
|
||||||
|
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// remove positive amount
|
||||||
|
if (bccomp($transaction->transaction_amount, '0') === -1) {
|
||||||
|
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transaction;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getSpentAccountSummary(): array
|
||||||
|
{
|
||||||
|
$transactions = $this->getExpenses();
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
$accountId = $transaction->account_id;
|
||||||
|
$result[$accountId] = $result[$accountId] ?? '0';
|
||||||
|
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getSpentCategorySummary(): array
|
||||||
|
{
|
||||||
|
$transactions = $this->getExpenses();
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
||||||
|
$transCatId = intval($transaction->transaction_category_id);
|
||||||
|
$categoryId = max($jrnlCatId, $transCatId);
|
||||||
|
|
||||||
|
$result[$categoryId] = $result[$categoryId] ?? '0';
|
||||||
|
$result[$categoryId] = bcadd($transaction->transaction_amount, $result[$categoryId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ namespace FireflyIII\Helpers\Collector;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Crypt;
|
use Crypt;
|
||||||
|
use DB;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
@ -16,6 +17,7 @@ use FireflyIII\Models\TransactionType;
|
|||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||||
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
@ -30,9 +32,10 @@ use Log;
|
|||||||
class JournalCollector implements JournalCollectorInterface
|
class JournalCollector implements JournalCollectorInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $accountIds = [];
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $count = 0;
|
private $count = 0;
|
||||||
|
|
||||||
/** @var array */
|
/** @var array */
|
||||||
private $fields
|
private $fields
|
||||||
= [
|
= [
|
||||||
@ -63,6 +66,8 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $joinedCategory = false;
|
private $joinedCategory = false;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
|
private $joinedOpposing = false;
|
||||||
|
/** @var bool */
|
||||||
private $joinedTag = false;
|
private $joinedTag = false;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $limit;
|
private $limit;
|
||||||
@ -112,6 +117,16 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
return $this->count;
|
return $this->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function disableFilter(): JournalCollectorInterface
|
||||||
|
{
|
||||||
|
$this->filterTransfers = false;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@ -133,6 +148,42 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function getOpposingAccount(): JournalCollectorInterface
|
||||||
|
{
|
||||||
|
$this->joinOpposingTables();
|
||||||
|
|
||||||
|
$accountIds = $this->accountIds;
|
||||||
|
$this->query->where(
|
||||||
|
function (EloquentBuilder $q1) use ($accountIds) {
|
||||||
|
// set 1
|
||||||
|
$q1->where(
|
||||||
|
function (EloquentBuilder $q2) use ($accountIds) {
|
||||||
|
// transactions.account_id in set
|
||||||
|
$q2->whereIn('transactions.account_id', $accountIds);
|
||||||
|
// opposing.account_id not in set
|
||||||
|
$q2->whereNotIn('opposing.account_id', $accountIds);
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// or set 2
|
||||||
|
$q1->orWhere(
|
||||||
|
function (EloquentBuilder $q3) use ($accountIds) {
|
||||||
|
// transactions.account_id not in set
|
||||||
|
$q3->whereNotIn('transactions.account_id', $accountIds);
|
||||||
|
// B in set
|
||||||
|
// opposing.account_id not in set
|
||||||
|
$q3->whereIn('opposing.account_id', $accountIds);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return LengthAwarePaginator
|
* @return LengthAwarePaginator
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@ -159,12 +210,15 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
if ($accounts->count() > 0) {
|
if ($accounts->count() > 0) {
|
||||||
$accountIds = $accounts->pluck('id')->toArray();
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
$this->query->whereIn('transactions.account_id', $accountIds);
|
$this->query->whereIn('transactions.account_id', $accountIds);
|
||||||
|
Log::debug(sprintf('setAccounts: %s', join(', ', $accountIds)));
|
||||||
|
$this->accountIds = $accountIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($accounts->count() > 1) {
|
if ($accounts->count() > 1) {
|
||||||
$this->filterTransfers = true;
|
$this->filterTransfers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +233,7 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
if ($accounts->count() > 0) {
|
if ($accounts->count() > 0) {
|
||||||
$accountIds = $accounts->pluck('id')->toArray();
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
$this->query->whereIn('transactions.account_id', $accountIds);
|
$this->query->whereIn('transactions.account_id', $accountIds);
|
||||||
|
$this->accountIds = $accountIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($accounts->count() > 1) {
|
if ($accounts->count() > 1) {
|
||||||
@ -223,6 +278,29 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
*
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setCategories(Collection $categories): JournalCollectorInterface
|
||||||
|
{
|
||||||
|
$categoryIds = $categories->pluck('id')->toArray();
|
||||||
|
if (count($categoryIds) === 0) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
$this->joinCategoryTables();
|
||||||
|
|
||||||
|
$this->query->where(
|
||||||
|
function (EloquentBuilder $q) use ($categoryIds) {
|
||||||
|
$q->whereIn('category_transaction.category_id', $categoryIds);
|
||||||
|
$q->orWhereIn('category_transaction_journal.category_id', $categoryIds);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
*
|
*
|
||||||
@ -389,6 +467,7 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
$set = $set->filter(
|
$set = $set->filter(
|
||||||
function (Transaction $transaction) {
|
function (Transaction $transaction) {
|
||||||
if (!($transaction->transaction_type_type === TransactionType::TRANSFER && bccomp($transaction->transaction_amount, '0') === -1)) {
|
if (!($transaction->transaction_type_type === TransactionType::TRANSFER && bccomp($transaction->transaction_amount, '0') === -1)) {
|
||||||
|
|
||||||
Log::debug(
|
Log::debug(
|
||||||
sprintf(
|
sprintf(
|
||||||
'Included journal #%d (transaction #%d) because its a %s with amount %f',
|
'Included journal #%d (transaction #%d) because its a %s with amount %f',
|
||||||
@ -443,6 +522,24 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
$this->joinedCategory = true;
|
$this->joinedCategory = true;
|
||||||
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
|
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
|
||||||
$this->query->leftJoin('category_transaction', 'category_transaction.transaction_id', '=', 'transactions.id');
|
$this->query->leftJoin('category_transaction', 'category_transaction.transaction_id', '=', 'transactions.id');
|
||||||
|
$this->fields[] = 'category_transaction_journal.category_id as transaction_journal_category_id';
|
||||||
|
$this->fields[] = 'category_transaction.category_id as transaction_category_id';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function joinOpposingTables()
|
||||||
|
{
|
||||||
|
if (!$this->joinedOpposing) {
|
||||||
|
// join opposing transaction (hard):
|
||||||
|
$this->query->leftJoin(
|
||||||
|
'transactions as opposing', function (JoinClause $join) {
|
||||||
|
$join->on('opposing.transaction_journal_id', '=', 'transactions.transaction_journal_id')
|
||||||
|
->where('opposing.identifier', '=', 'transactions.identifier')
|
||||||
|
->where('opposing.amount', '=', DB::raw('transactions.amount * -1'));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->fields[] = 'opposing.account_id as opposing_account_id';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,5 +578,4 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
return $query;
|
return $query;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -12,6 +12,7 @@
|
|||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
namespace FireflyIII\Helpers\Collector;
|
namespace FireflyIII\Helpers\Collector;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
@ -32,11 +33,21 @@ interface JournalCollectorInterface
|
|||||||
*/
|
*/
|
||||||
public function count(): int;
|
public function count(): int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function disableFilter(): JournalCollectorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getJournals(): Collection;
|
public function getJournals(): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function getOpposingAccount(): JournalCollectorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return LengthAwarePaginator
|
* @return LengthAwarePaginator
|
||||||
*/
|
*/
|
||||||
@ -68,6 +79,13 @@ interface JournalCollectorInterface
|
|||||||
*/
|
*/
|
||||||
public function setBudget(Budget $budget): JournalCollectorInterface;
|
public function setBudget(Budget $budget): JournalCollectorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
*
|
||||||
|
* @return JournalCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setCategories(Collection $categories): JournalCollectorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
*
|
*
|
||||||
|
@ -16,10 +16,13 @@ namespace FireflyIII\Http\Controllers\Chart;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@ -48,7 +51,6 @@ class CategoryController extends Controller
|
|||||||
$this->generator = app(CategoryChartGeneratorInterface::class);
|
$this->generator = app(CategoryChartGeneratorInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an overview for a category for all time, per month/week/year.
|
* Show an overview for a category for all time, per month/week/year.
|
||||||
*
|
*
|
||||||
@ -109,6 +111,51 @@ class CategoryController extends Controller
|
|||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $others
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function expensePieChart(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var CategoryRepositoryInterface $repository */
|
||||||
|
$repository = app(CategoryRepositoryInterface::class);
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$names = [];
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)
|
||||||
|
->setTypes([TransactionType::WITHDRAWAL])
|
||||||
|
->setCategories($categories);
|
||||||
|
$set = $collector->getSumPerCategory();
|
||||||
|
$result = [];
|
||||||
|
$total = '0';
|
||||||
|
foreach ($set as $categoryId => $amount) {
|
||||||
|
if (!isset($names[$categoryId])) {
|
||||||
|
$category = $repository->find(intval($categoryId));
|
||||||
|
$names[$categoryId] = $category->name;
|
||||||
|
}
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$result[] = ['name' => $names[$categoryId], 'id' => $categoryId, 'amount' => $amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
|
$sum = bcmul($collector->getSum(), '-1');
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($result);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param CRI $repository
|
* @param CRI $repository
|
||||||
* @param AccountRepositoryInterface $accountRepository
|
* @param AccountRepositoryInterface $accountRepository
|
||||||
@ -153,6 +200,49 @@ class CategoryController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $others
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function incomePieChart(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var CategoryRepositoryInterface $repository */
|
||||||
|
$repository = app(CategoryRepositoryInterface::class);
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$names = [];
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setCategories($categories);
|
||||||
|
$set = $collector->getSumPerCategory();
|
||||||
|
$result = [];
|
||||||
|
$total = '0';
|
||||||
|
foreach ($set as $categoryId => $amount) {
|
||||||
|
if (!isset($names[$categoryId])) {
|
||||||
|
$category = $repository->find(intval($categoryId));
|
||||||
|
$names[$categoryId] = $category->name;
|
||||||
|
}
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$result[] = ['name' => $names[$categoryId], 'id' => $categoryId, 'amount' => $amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
||||||
|
$sum = $collector->getSum();
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($result);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param CRI $repository
|
* @param CRI $repository
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
/* globals $, Chart, currencySymbol,mon_decimal_point ,accounting, mon_thousands_sep, frac_digits */
|
/* globals $, Chart, currencySymbol,mon_decimal_point ,accounting, mon_thousands_sep, frac_digits */
|
||||||
|
|
||||||
|
var allCharts = {};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Make some colours:
|
Make some colours:
|
||||||
*/
|
*/
|
||||||
@ -29,7 +31,6 @@ var colourSet = [
|
|||||||
[240, 98, 146],
|
[240, 98, 146],
|
||||||
[0, 121, 107],
|
[0, 121, 107],
|
||||||
[194, 24, 91]
|
[194, 24, 91]
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
var fillColors = [];
|
var fillColors = [];
|
||||||
@ -234,6 +235,11 @@ function lineChart(URL, container, options) {
|
|||||||
function areaChart(URL, container, options) {
|
function areaChart(URL, container, options) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
if ($('#' + container).length === 0) {
|
||||||
|
console.log('No container called ' + container + ' was found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.getJSON(URL).done(function (data) {
|
$.getJSON(URL).done(function (data) {
|
||||||
var ctx = document.getElementById(container).getContext("2d");
|
var ctx = document.getElementById(container).getContext("2d");
|
||||||
var newData = {};
|
var newData = {};
|
||||||
@ -358,14 +364,30 @@ function stackedColumnChart(URL, container, options) {
|
|||||||
function pieChart(URL, container, options) {
|
function pieChart(URL, container, options) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
if ($('#' + container).length === 0) {
|
||||||
|
console.log('No container called ' + container + ' was found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.getJSON(URL).done(function (data) {
|
$.getJSON(URL).done(function (data) {
|
||||||
|
|
||||||
|
if (allCharts.hasOwnProperty(container)) {
|
||||||
|
console.log('Will draw updated pie chart');
|
||||||
|
|
||||||
|
allCharts[container].data.datasets = data.datasets;
|
||||||
|
allCharts[container].data.labels = data.labels;
|
||||||
|
allCharts[container].update();
|
||||||
|
} else {
|
||||||
|
// new chart!
|
||||||
|
console.log('Will draw new pie chart');
|
||||||
var ctx = document.getElementById(container).getContext("2d");
|
var ctx = document.getElementById(container).getContext("2d");
|
||||||
new Chart(ctx, {
|
allCharts[container] = new Chart(ctx, {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: data,
|
data: data,
|
||||||
options: defaultPieOptions
|
options: defaultPieOptions
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}).fail(function () {
|
}).fail(function () {
|
||||||
$('#' + container).addClass('general-chart-error');
|
$('#' + container).addClass('general-chart-error');
|
||||||
|
10
public/js/ff/reports/category/all.js
Normal file
10
public/js/ff/reports/category/all.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* all.js
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
57
public/js/ff/reports/category/month.js
Normal file
57
public/js/ff/reports/category/month.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* month.js
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
"use strict";
|
||||||
|
drawChart();
|
||||||
|
$('#categories-in-pie-chart-checked').on('change', redrawCatInPie);
|
||||||
|
$('#categories-out-pie-chart-checked').on('change', redrawCatOutPie);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function drawChart() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// month view:
|
||||||
|
|
||||||
|
// draw pie chart of income, depending on "show other transactions too":
|
||||||
|
redrawCatInPie();
|
||||||
|
redrawCatOutPie();
|
||||||
|
}
|
||||||
|
|
||||||
|
function redrawCatOutPie() {
|
||||||
|
"use strict";
|
||||||
|
var checkbox = $('#categories-out-pie-chart-checked');
|
||||||
|
var container = 'categories-out-pie-chart';
|
||||||
|
|
||||||
|
//
|
||||||
|
var others = '0';
|
||||||
|
// check if box is checked:
|
||||||
|
if (checkbox.prop('checked')) {
|
||||||
|
others = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
pieChart('chart/category/' + accountIds + '/' + categoryIds + '/' + startDate + '/' + endDate + '/' + others + '/expense', container);
|
||||||
|
}
|
||||||
|
|
||||||
|
function redrawCatInPie() {
|
||||||
|
"use strict";
|
||||||
|
var checkbox = $('#categories-in-pie-chart-checked');
|
||||||
|
var container = 'categories-in-pie-chart';
|
||||||
|
|
||||||
|
//
|
||||||
|
var others = '0';
|
||||||
|
// check if box is checked:
|
||||||
|
if (checkbox.prop('checked')) {
|
||||||
|
others = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
pieChart('chart/category/' + accountIds + '/' + categoryIds + '/' + startDate + '/' + endDate + '/' + others + '/income', container);
|
||||||
|
}
|
@ -8,14 +8,135 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
Summary here. Accounts and categories involved. Summary of in/out
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'accounts'|_ }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
<div class="box-body table-responsive no-padding">
|
||||||
Pie chart with spending (aka all withdrawals in category). Optional checkbox to include all other transactions.
|
<table class="table table-hover sortable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'name'|_ }}</th>
|
||||||
|
<th>{{ 'earned'|_ }}</th>
|
||||||
|
<th>{{ 'spent'|_ }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for account in accounts %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{ route('accounts.show', account.id) }}" title="{{ account.name }}">{{ account.name }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if accountSummary[account.id] %}
|
||||||
|
{{ accountSummary[account.id].earned|formatAmount }}
|
||||||
|
{% else %}
|
||||||
|
{{ 0|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if accountSummary[account.id] %}
|
||||||
|
{{ accountSummary[account.id].spent|formatAmount }}
|
||||||
|
{% else %}
|
||||||
|
{{ 0|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</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="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'categories'|_ }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body table-responsive no-padding">
|
||||||
|
<table class="table table-hover sortable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'name'|_ }}</th>
|
||||||
|
<th>{{ 'earned'|_ }}</th>
|
||||||
|
<th>{{ 'spent'|_ }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for category in categories %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{ route('categories.show', category.id) }}" title="{{ category.name }}">{{ category.name }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if categorySummary[category.id] %}
|
||||||
|
{{ categorySummary[category.id].earned|formatAmount }}
|
||||||
|
{% else %}
|
||||||
|
{{ 0|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if categorySummary[category.id] %}
|
||||||
|
{{ categorySummary[category.id].spent|formatAmount }}
|
||||||
|
{% else %}
|
||||||
|
{{ 0|formatAmount }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if categories.count > 1 %}
|
||||||
|
<div class="col-lg-2">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'income_per_category'|_ }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
<canvas id="categories-in-pie-chart" style="width:100px;height:100px;" height="100"></canvas>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="categories-in-pie-chart-checked"> Include transactions not in these categories
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-2">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'expense_per_category'|_ }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
<canvas id="categories-out-pie-chart" style="width:100px;height:100px;" height="100"></canvas>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="categories-out-pie-chart-checked"> Include transactions not in these categories
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if accounts.count > 1 %}
|
||||||
|
<div class="col-lg-2">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'income_per_account'|_ }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-2">
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">{{ 'expense_per_account'|_ }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{#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="row">
|
||||||
@ -59,6 +180,23 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
|
<script type="text/javascript" src="js/lib/Chart.bundle.min.js"></script>
|
||||||
|
<script type="text/javascript" src="js/ff/charts.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
// to report another URL:
|
||||||
|
var startDate = '{{ start.format('Ymd') }}';
|
||||||
|
var endDate = '{{ end.format('Ymd') }}';
|
||||||
|
var accountIds = '{{ accountIds }}';
|
||||||
|
var categoryIds = '{{ categoryIds }}';
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript" src="js/ff/reports/category/all.js"></script>
|
||||||
|
<script type="text/javascript" src="js/ff/reports/category/month.js"></script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
|
@ -204,11 +204,14 @@ Route::group(
|
|||||||
|
|
||||||
// categories:
|
// categories:
|
||||||
Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']);
|
Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']);
|
||||||
|
|
||||||
Route::get('/chart/category/{category}/period', ['uses' => 'Chart\CategoryController@currentPeriod']);
|
Route::get('/chart/category/{category}/period', ['uses' => 'Chart\CategoryController@currentPeriod']);
|
||||||
Route::get('/chart/category/{category}/period/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
|
Route::get('/chart/category/{category}/period/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
|
||||||
Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']);
|
Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']);
|
||||||
|
|
||||||
|
// these charts are used in reports:
|
||||||
|
Route::get('/chart/category/{accountList}/{categoryList}/{start_date}/{end_date}/{others}/income', ['uses' => 'Chart\CategoryController@incomePieChart']);
|
||||||
|
Route::get('/chart/category/{accountList}/{categoryList}/{start_date}/{end_date}/{others}/expense', ['uses' => 'Chart\CategoryController@expensePieChart']);
|
||||||
|
|
||||||
// piggy banks:
|
// piggy banks:
|
||||||
Route::get('/chart/piggy-bank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
|
Route::get('/chart/piggy-bank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user