mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-25 23:06:14 +00:00
Fixes all charts in future category report.
This commit is contained in:
@@ -118,6 +118,18 @@ class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function period(Collection $entries): array
|
||||||
|
{
|
||||||
|
return $this->all($entries);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $entries
|
* @param array $entries
|
||||||
*
|
*
|
||||||
@@ -133,6 +145,11 @@ class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
|
|||||||
];
|
];
|
||||||
$index = 0;
|
$index = 0;
|
||||||
foreach ($entries as $entry) {
|
foreach ($entries as $entry) {
|
||||||
|
|
||||||
|
if (bccomp($entry['amount'], '0') === -1) {
|
||||||
|
$entry['amount'] = bcmul($entry['amount'], '-1');
|
||||||
|
}
|
||||||
|
|
||||||
$data['datasets'][0]['data'][] = round($entry['amount'], 2);
|
$data['datasets'][0]['data'][] = round($entry['amount'], 2);
|
||||||
$data['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
|
$data['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
|
||||||
$data['labels'][] = $entry['name'];
|
$data['labels'][] = $entry['name'];
|
||||||
@@ -142,18 +159,6 @@ class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function period(Collection $entries): array
|
|
||||||
{
|
|
||||||
return $this->all($entries);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
* @param Collection $entries
|
* @param Collection $entries
|
||||||
|
@@ -27,7 +27,7 @@ use Log;
|
|||||||
*
|
*
|
||||||
* @package FireflyIII\Generator\Report\Category
|
* @package FireflyIII\Generator\Report\Category
|
||||||
*/
|
*/
|
||||||
class MonthReportGenerator implements ReportGeneratorInterface
|
class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||||
{
|
{
|
||||||
/** @var Collection */
|
/** @var Collection */
|
||||||
private $accounts;
|
private $accounts;
|
||||||
@@ -38,68 +38,6 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
/** @var Carbon */
|
/** @var Carbon */
|
||||||
private $start;
|
private $start;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $collection
|
|
||||||
* @param array $accounts
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public static function filterExpenses(Collection $collection, array $accounts): Collection
|
|
||||||
{
|
|
||||||
$result = $collection->filter(
|
|
||||||
function (Transaction $transaction) use ($accounts) {
|
|
||||||
$opposing = $transaction->opposing_account_id;
|
|
||||||
// remove internal transfer
|
|
||||||
if (in_array($opposing, $accounts)) {
|
|
||||||
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 $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $collection
|
|
||||||
* @param array $accounts
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public static function filterIncome(Collection $collection, array $accounts): Collection
|
|
||||||
{
|
|
||||||
$result = $collection->filter(
|
|
||||||
function (Transaction $transaction) use ($accounts) {
|
|
||||||
$opposing = $transaction->opposing_account_id;
|
|
||||||
// remove internal transfer
|
|
||||||
if (in_array($opposing, $accounts)) {
|
|
||||||
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 $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
91
app/Generator/Report/Category/Support.php
Normal file
91
app/Generator/Report/Category/Support.php
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Support.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Report\Category;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Support
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Report\Category
|
||||||
|
*/
|
||||||
|
class Support
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $collection
|
||||||
|
* @param array $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public static function filterExpenses(Collection $collection, array $accounts): Collection
|
||||||
|
{
|
||||||
|
$result = $collection->filter(
|
||||||
|
function (Transaction $transaction) use ($accounts) {
|
||||||
|
$opposing = $transaction->opposing_account_id;
|
||||||
|
// remove internal transfer
|
||||||
|
if (in_array($opposing, $accounts)) {
|
||||||
|
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 $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $collection
|
||||||
|
* @param array $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public static function filterIncome(Collection $collection, array $accounts): Collection
|
||||||
|
{
|
||||||
|
$result = $collection->filter(
|
||||||
|
function (Transaction $transaction) use ($accounts) {
|
||||||
|
$opposing = $transaction->opposing_account_id;
|
||||||
|
// remove internal transfer
|
||||||
|
if (in_array($opposing, $accounts)) {
|
||||||
|
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 $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -16,15 +16,10 @@ 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\Generator\Report\Category\MonthReportGenerator;
|
|
||||||
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\Transaction;
|
|
||||||
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;
|
||||||
@@ -113,72 +108,6 @@ 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);
|
|
||||||
/** @var bool $others */
|
|
||||||
$others = intval($others) === 1;
|
|
||||||
$names = [];
|
|
||||||
|
|
||||||
// collect journals (just like the category report does):
|
|
||||||
$collector = new JournalCollector(auth()->user());
|
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
|
||||||
->setCategories($categories)->getOpposingAccount()->disableFilter();
|
|
||||||
$accountIds = $accounts->pluck('id')->toArray();
|
|
||||||
$transactions = $collector->getJournals();
|
|
||||||
$set = MonthReportGenerator::filterExpenses($transactions, $accountIds);
|
|
||||||
|
|
||||||
// group by category ID:
|
|
||||||
$grouped = [];
|
|
||||||
/** @var Transaction $transaction */
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
|
||||||
$transCatId = intval($transaction->transaction_category_id);
|
|
||||||
$categoryId = max($jrnlCatId, $transCatId);
|
|
||||||
|
|
||||||
$grouped[$categoryId] = $grouped[$categoryId] ?? '0';
|
|
||||||
$amount = bcmul($transaction->transaction_amount, '-1');
|
|
||||||
$grouped[$categoryId] = bcadd($amount, $grouped[$categoryId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop and show the grouped results:
|
|
||||||
$result = [];
|
|
||||||
$total = '0';
|
|
||||||
foreach ($grouped 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
// also collect others?
|
|
||||||
// TODO include transfers
|
|
||||||
if ($others) {
|
|
||||||
$collector = new JournalCollector(auth()->user());
|
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
|
|
||||||
$journals = $collector->getJournals();
|
|
||||||
$sum = bcmul(strval($journals->sum('transaction_amount')), '-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
|
||||||
@@ -223,71 +152,6 @@ 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 = [];
|
|
||||||
|
|
||||||
// collect journals (just like the category report does):
|
|
||||||
$collector = new JournalCollector(auth()->user());
|
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
|
||||||
->setCategories($categories)->getOpposingAccount();
|
|
||||||
$accountIds = $accounts->pluck('id')->toArray();
|
|
||||||
$transactions = $collector->getJournals();
|
|
||||||
$set = MonthReportGenerator::filterIncome($transactions, $accountIds);
|
|
||||||
|
|
||||||
// group by category ID:
|
|
||||||
$grouped = [];
|
|
||||||
/** @var Transaction $transaction */
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
|
||||||
$transCatId = intval($transaction->transaction_category_id);
|
|
||||||
$categoryId = max($jrnlCatId, $transCatId);
|
|
||||||
|
|
||||||
$grouped[$categoryId] = $grouped[$categoryId] ?? '0';
|
|
||||||
$grouped[$categoryId] = bcadd($transaction->transaction_amount, $grouped[$categoryId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop and show the grouped results:
|
|
||||||
$result = [];
|
|
||||||
$total = '0';
|
|
||||||
foreach ($grouped 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
// also collect others?
|
|
||||||
// TODO include transfers
|
|
||||||
if ($others) {
|
|
||||||
$collector = new JournalCollector(auth()->user());
|
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
|
||||||
$journals = $collector->getJournals();
|
|
||||||
$sum = strval($journals->sum('transaction_amount'));
|
|
||||||
$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
|
||||||
@@ -307,6 +171,7 @@ class CategoryController extends Controller
|
|||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param CRI $repository
|
* @param CRI $repository
|
||||||
* @param Category $category
|
* @param Category $category
|
||||||
|
360
app/Http/Controllers/Chart/CategoryReportController.php
Normal file
360
app/Http/Controllers/Chart/CategoryReportController.php
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CategoryReportController.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Controllers\Chart;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
|
||||||
|
use FireflyIII\Generator\Report\Category\MonthReportGenerator;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
use Response;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Separate controller because many helper functions are shared.
|
||||||
|
*
|
||||||
|
* TODO much of this code is actually repeated. First for the object (category, account), then for the direction (in / out).
|
||||||
|
*
|
||||||
|
* Class CategoryReportController
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Controllers\Chart
|
||||||
|
*/
|
||||||
|
class CategoryReportController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var AccountRepositoryInterface */
|
||||||
|
private $accountRepository;
|
||||||
|
/** @var CategoryRepositoryInterface */
|
||||||
|
private $categoryRepository;
|
||||||
|
/** @var CategoryChartGeneratorInterface */
|
||||||
|
private $generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->middleware(
|
||||||
|
function ($request, $next) {
|
||||||
|
$this->generator = app(CategoryChartGeneratorInterface::class);
|
||||||
|
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||||
|
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $others
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function accountExpense(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$names = [];
|
||||||
|
|
||||||
|
// collect journals (just like the category report does):
|
||||||
|
$set = $this->getExpenses($accounts, $categories, $start, $end);
|
||||||
|
$grouped = $this->groupByOpposingAccount($set);
|
||||||
|
|
||||||
|
// show the grouped results:
|
||||||
|
$result = [];
|
||||||
|
$total = '0';
|
||||||
|
foreach ($grouped as $accountId => $amount) {
|
||||||
|
if (!isset($names[$accountId])) {
|
||||||
|
$account = $this->accountRepository->find(intval($accountId));
|
||||||
|
$names[$accountId] = $account->name;
|
||||||
|
}
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$result[] = ['name' => $names[$accountId], 'id' => $accountId, 'amount' => $amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
// also collect all transactions NOT in these categories.
|
||||||
|
// TODO include transfers
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
|
$journals = $collector->getJournals();
|
||||||
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
|
$sum = bcmul($sum, '-1');
|
||||||
|
Log::debug(sprintf('Sum of others in accountExpense is %f', $sum));
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($result);
|
||||||
|
|
||||||
|
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 accountIncome(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$names = [];
|
||||||
|
|
||||||
|
// collect journals (just like the category report does):
|
||||||
|
$set = $this->getIncome($accounts, $categories, $start, $end);
|
||||||
|
$grouped = $this->groupByOpposingAccount($set);
|
||||||
|
|
||||||
|
// loop and show the grouped results:
|
||||||
|
$result = [];
|
||||||
|
$total = '0';
|
||||||
|
foreach ($grouped as $accountId => $amount) {
|
||||||
|
if (!isset($names[$accountId])) {
|
||||||
|
$account = $this->accountRepository->find(intval($accountId));
|
||||||
|
$names[$accountId] = $account->name;
|
||||||
|
}
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$result[] = ['name' => $names[$accountId], 'id' => $accountId, 'amount' => $amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
// also collect others?
|
||||||
|
// TODO include transfers
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
||||||
|
$journals = $collector->getJournals();
|
||||||
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
|
Log::debug(sprintf('Sum of others in accountIncome is %f', $sum));
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($result);
|
||||||
|
|
||||||
|
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 categoryExpense(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$names = [];
|
||||||
|
|
||||||
|
// collect journals (just like the category report does):
|
||||||
|
$set = $this->getExpenses($accounts, $categories, $start, $end);
|
||||||
|
$grouped = $this->groupByCategory($set);
|
||||||
|
|
||||||
|
// show the grouped results:
|
||||||
|
$result = [];
|
||||||
|
$total = '0';
|
||||||
|
foreach ($grouped as $categoryId => $amount) {
|
||||||
|
if (!isset($names[$categoryId])) {
|
||||||
|
$category = $this->categoryRepository->find(intval($categoryId));
|
||||||
|
$names[$categoryId] = $category->name;
|
||||||
|
}
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$result[] = ['name' => $names[$categoryId], 'id' => $categoryId, 'amount' => $amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
// also collect all transactions NOT in these categories.
|
||||||
|
// TODO include transfers
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
|
$journals = $collector->getJournals();
|
||||||
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
|
$sum = bcmul($sum, '-1');
|
||||||
|
Log::debug(sprintf('Sum of others in categoryExpense is %f', $sum));
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($result);
|
||||||
|
|
||||||
|
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 categoryIncome(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$names = [];
|
||||||
|
|
||||||
|
// collect journals (just like the category report does):
|
||||||
|
$set = $this->getIncome($accounts, $categories, $start, $end);
|
||||||
|
$grouped = $this->groupByCategory($set);
|
||||||
|
|
||||||
|
// loop and show the grouped results:
|
||||||
|
$result = [];
|
||||||
|
$total = '0';
|
||||||
|
foreach ($grouped as $categoryId => $amount) {
|
||||||
|
if (!isset($names[$categoryId])) {
|
||||||
|
$category = $this->categoryRepository->find(intval($categoryId));
|
||||||
|
$names[$categoryId] = $category->name;
|
||||||
|
}
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$result[] = ['name' => $names[$categoryId], 'id' => $categoryId, 'amount' => $amount];
|
||||||
|
}
|
||||||
|
|
||||||
|
// also collect others?
|
||||||
|
// TODO include transfers
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
||||||
|
$journals = $collector->getJournals();
|
||||||
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
|
Log::debug(sprintf('Sum of others in categoryIncome is %f', $sum));
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($result);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getExpenses(Collection $accounts, Collection $categories, Carbon $start, Carbon $end): Collection
|
||||||
|
{
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||||
|
->setCategories($categories)->getOpposingAccount()->disableFilter();
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$transactions = $collector->getJournals();
|
||||||
|
$set = MonthReportGenerator::filterExpenses($transactions, $accountIds);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getIncome(Collection $accounts, Collection $categories, Carbon $start, Carbon $end): Collection
|
||||||
|
{
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
||||||
|
->setCategories($categories)->getOpposingAccount();
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$transactions = $collector->getJournals();
|
||||||
|
$set = MonthReportGenerator::filterIncome($transactions, $accountIds);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function groupByAccount(Collection $set): array
|
||||||
|
{
|
||||||
|
// group by category ID:
|
||||||
|
$grouped = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$accountId = $transaction->account_id;
|
||||||
|
$grouped[$accountId] = $grouped[$accountId] ?? '0';
|
||||||
|
$grouped[$accountId] = bcadd($transaction->transaction_amount, $grouped[$accountId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grouped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function groupByCategory(Collection $set): array
|
||||||
|
{
|
||||||
|
// group by category ID:
|
||||||
|
$grouped = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
||||||
|
$transCatId = intval($transaction->transaction_category_id);
|
||||||
|
$categoryId = max($jrnlCatId, $transCatId);
|
||||||
|
$grouped[$categoryId] = $grouped[$categoryId] ?? '0';
|
||||||
|
$grouped[$categoryId] = bcadd($transaction->transaction_amount, $grouped[$categoryId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grouped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function groupByOpposingAccount(Collection $set): array
|
||||||
|
{
|
||||||
|
$grouped = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$accountId = $transaction->opposing_account_id;
|
||||||
|
$grouped[$accountId] = $grouped[$accountId] ?? '0';
|
||||||
|
$grouped[$accountId] = bcadd($transaction->transaction_amount, $grouped[$accountId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grouped;
|
||||||
|
}
|
||||||
|
}
|
@@ -8,11 +8,33 @@
|
|||||||
* See the LICENSE file for details.
|
* See the LICENSE file for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// it's hard coded, but what you're gonna do?
|
||||||
|
var catInUri = 'chart/category/' + accountIds + '/' + categoryIds + '/' + startDate + '/' + endDate + '/OTHERS/income';
|
||||||
|
var catOutUri = 'chart/category/' + accountIds + '/' + categoryIds + '/' + startDate + '/' + endDate + '/OTHERS/expense';
|
||||||
|
var accInUri = 'chart/account/' + accountIds + '/' + categoryIds + '/' + startDate + '/' + endDate + '/OTHERS/income';
|
||||||
|
var accOutUri = 'chart/account/' + accountIds + '/' + categoryIds + '/' + startDate + '/' + endDate + '/OTHERS/expense';
|
||||||
|
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
drawChart();
|
drawChart();
|
||||||
$('#categories-in-pie-chart-checked').on('change', redrawCatInPie);
|
|
||||||
$('#categories-out-pie-chart-checked').on('change', redrawCatOutPie);
|
$('#categories-in-pie-chart-checked').on('change', function () {
|
||||||
|
redrawPieChart('categories-in-pie-chart', catInUri);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#categories-out-pie-chart-checked').on('change', function () {
|
||||||
|
redrawPieChart('categories-out-pie-chart', catOutUri);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#accounts-in-pie-chart-checked').on('change', function () {
|
||||||
|
redrawPieChart('accounts-in-pie-chart', accInUri);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#accounts-out-pie-chart-checked').on('change', function () {
|
||||||
|
redrawPieChart('accounts-out-pie-chart', accOutUri);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -22,36 +44,24 @@ function drawChart() {
|
|||||||
// month view:
|
// month view:
|
||||||
|
|
||||||
// draw pie chart of income, depending on "show other transactions too":
|
// draw pie chart of income, depending on "show other transactions too":
|
||||||
redrawCatInPie();
|
redrawPieChart('categories-in-pie-chart', catInUri);
|
||||||
redrawCatOutPie();
|
redrawPieChart('categories-out-pie-chart', catOutUri);
|
||||||
|
redrawPieChart('accounts-in-pie-chart', accInUri);
|
||||||
|
redrawPieChart('accounts-out-pie-chart', accOutUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
function redrawCatOutPie() {
|
function redrawPieChart(container, uri) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var checkbox = $('#categories-out-pie-chart-checked');
|
var checkbox = $('#' + container + '-checked');
|
||||||
var container = 'categories-out-pie-chart';
|
|
||||||
|
|
||||||
//
|
|
||||||
var others = '0';
|
var others = '0';
|
||||||
// check if box is checked:
|
// check if box is checked:
|
||||||
if (checkbox.prop('checked')) {
|
if (checkbox.prop('checked')) {
|
||||||
others = '1';
|
others = '1';
|
||||||
}
|
}
|
||||||
|
uri = uri.replace('OTHERS', others);
|
||||||
|
console.log('URI for ' + container + ' is ' + uri);
|
||||||
|
|
||||||
|
pieChart(uri, container);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
@@ -123,6 +123,10 @@
|
|||||||
<h3 class="box-title">{{ 'income_per_account'|_ }}</h3>
|
<h3 class="box-title">{{ 'income_per_account'|_ }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
|
<canvas id="accounts-in-pie-chart" style="width:100px;height:100px;" height="100"></canvas>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="accounts-in-pie-chart-checked"> Include transactions not in these categories
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,6 +136,10 @@
|
|||||||
<h3 class="box-title">{{ 'expense_per_account'|_ }}</h3>
|
<h3 class="box-title">{{ 'expense_per_account'|_ }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
|
<canvas id="accounts-out-pie-chart" style="width:100px;height:100px;" height="100"></canvas>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="accounts-out-pie-chart-checked"> Include transactions not in these categories
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -208,9 +208,16 @@ Route::group(
|
|||||||
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:
|
// these charts are used in reports (category 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}/income',
|
||||||
Route::get('/chart/category/{accountList}/{categoryList}/{start_date}/{end_date}/{others}/expense', ['uses' => 'Chart\CategoryController@expensePieChart']);
|
['uses' => 'Chart\CategoryReportController@categoryIncome']);
|
||||||
|
Route::get('/chart/category/{accountList}/{categoryList}/{start_date}/{end_date}/{others}/expense',
|
||||||
|
['uses' => 'Chart\CategoryReportController@categoryExpense']);
|
||||||
|
|
||||||
|
Route::get('/chart/account/{accountList}/{categoryList}/{start_date}/{end_date}/{others}/income',
|
||||||
|
['uses' => 'Chart\CategoryReportController@accountIncome']);
|
||||||
|
Route::get('/chart/account/{accountList}/{categoryList}/{start_date}/{end_date}/{others}/expense',
|
||||||
|
['uses' => 'Chart\CategoryReportController@accountExpense']);
|
||||||
|
|
||||||
// piggy banks:
|
// piggy banks:
|
||||||
Route::get('/chart/piggy-bank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
|
Route::get('/chart/piggy-bank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
|
||||||
|
Reference in New Issue
Block a user