diff --git a/app/Generator/Chart/Category/CategoryChartGeneratorInterface.php b/app/Generator/Chart/Category/CategoryChartGeneratorInterface.php
index e17022d9b6..e0444c1cba 100644
--- a/app/Generator/Chart/Category/CategoryChartGeneratorInterface.php
+++ b/app/Generator/Chart/Category/CategoryChartGeneratorInterface.php
@@ -23,6 +23,13 @@ use Illuminate\Support\Collection;
interface CategoryChartGeneratorInterface
{
+ /**
+ * @param array $data
+ *
+ * @return array
+ */
+ public function pieChart(array $data): array;
+
/**
* @param Collection $entries
*
diff --git a/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php b/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
index 560b4f95bb..9e6221f24b 100644
--- a/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
+++ b/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
@@ -12,6 +12,7 @@
declare(strict_types = 1);
namespace FireflyIII\Generator\Chart\Category;
+use FireflyIII\Support\ChartColour;
use Illuminate\Support\Collection;
@@ -117,6 +118,30 @@ class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
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
diff --git a/app/Generator/Report/Category/MonthReportGenerator.php b/app/Generator/Report/Category/MonthReportGenerator.php
index d2bd5ec3c2..623d65fef1 100644
--- a/app/Generator/Report/Category/MonthReportGenerator.php
+++ b/app/Generator/Report/Category/MonthReportGenerator.php
@@ -16,7 +16,11 @@ namespace FireflyIII\Generator\Report\Category;
use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
+use FireflyIII\Helpers\Collector\JournalCollector;
+use FireflyIII\Models\Transaction;
+use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
+use Log;
/**
* Class MonthReportGenerator
@@ -39,13 +43,17 @@ class MonthReportGenerator implements ReportGeneratorInterface
*/
public function generate(): string
{
- $accountIds = join(',', $this->accounts->pluck('id')->toArray());
- $reportType = 'category';
+ $accountIds = join(',', $this->accounts->pluck('id')->toArray());
+ $categoryIds = join(',', $this->categories->pluck('id')->toArray());
+ $reportType = 'category';
+ $accountSummary = $this->getAccountSummary();
+ $categorySummary = $this->getCategorySummary();
// 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('categories', $this->categories)
+ ->with('accounts', $this->accounts)
->render();
}
@@ -96,4 +104,226 @@ class MonthReportGenerator implements ReportGeneratorInterface
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;
+
+
+ }
}
\ No newline at end of file
diff --git a/app/Helpers/Collector/JournalCollector.php b/app/Helpers/Collector/JournalCollector.php
index 11406b025b..349b1d2b99 100644
--- a/app/Helpers/Collector/JournalCollector.php
+++ b/app/Helpers/Collector/JournalCollector.php
@@ -6,6 +6,7 @@ namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon;
use Crypt;
+use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
@@ -16,6 +17,7 @@ use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
+use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
@@ -30,9 +32,10 @@ use Log;
class JournalCollector implements JournalCollectorInterface
{
+ /** @var array */
+ private $accountIds = [];
/** @var int */
private $count = 0;
-
/** @var array */
private $fields
= [
@@ -63,6 +66,8 @@ class JournalCollector implements JournalCollectorInterface
/** @var bool */
private $joinedCategory = false;
/** @var bool */
+ private $joinedOpposing = false;
+ /** @var bool */
private $joinedTag = false;
/** @var int */
private $limit;
@@ -112,6 +117,16 @@ class JournalCollector implements JournalCollectorInterface
return $this->count;
}
+ /**
+ * @return JournalCollectorInterface
+ */
+ public function disableFilter(): JournalCollectorInterface
+ {
+ $this->filterTransfers = false;
+
+ return $this;
+ }
+
/**
* @return Collection
*/
@@ -133,6 +148,42 @@ class JournalCollector implements JournalCollectorInterface
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
* @throws FireflyException
@@ -159,12 +210,15 @@ class JournalCollector implements JournalCollectorInterface
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('transactions.account_id', $accountIds);
+ Log::debug(sprintf('setAccounts: %s', join(', ', $accountIds)));
+ $this->accountIds = $accountIds;
}
if ($accounts->count() > 1) {
$this->filterTransfers = true;
}
+
return $this;
}
@@ -179,6 +233,7 @@ class JournalCollector implements JournalCollectorInterface
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('transactions.account_id', $accountIds);
+ $this->accountIds = $accountIds;
}
if ($accounts->count() > 1) {
@@ -223,6 +278,29 @@ class JournalCollector implements JournalCollectorInterface
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
*
@@ -389,6 +467,7 @@ class JournalCollector implements JournalCollectorInterface
$set = $set->filter(
function (Transaction $transaction) {
if (!($transaction->transaction_type_type === TransactionType::TRANSFER && bccomp($transaction->transaction_amount, '0') === -1)) {
+
Log::debug(
sprintf(
'Included journal #%d (transaction #%d) because its a %s with amount %f',
@@ -443,6 +522,24 @@ class JournalCollector implements JournalCollectorInterface
$this->joinedCategory = true;
$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->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;
}
-
}
\ No newline at end of file
diff --git a/app/Helpers/Collector/JournalCollectorInterface.php b/app/Helpers/Collector/JournalCollectorInterface.php
index 26ad19b30a..b451a111ae 100644
--- a/app/Helpers/Collector/JournalCollectorInterface.php
+++ b/app/Helpers/Collector/JournalCollectorInterface.php
@@ -12,6 +12,7 @@
declare(strict_types = 1);
namespace FireflyIII\Helpers\Collector;
+
use Carbon\Carbon;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
@@ -32,11 +33,21 @@ interface JournalCollectorInterface
*/
public function count(): int;
+ /**
+ * @return JournalCollectorInterface
+ */
+ public function disableFilter(): JournalCollectorInterface;
+
/**
* @return Collection
*/
public function getJournals(): Collection;
+ /**
+ * @return JournalCollectorInterface
+ */
+ public function getOpposingAccount(): JournalCollectorInterface;
+
/**
* @return LengthAwarePaginator
*/
@@ -68,6 +79,13 @@ interface JournalCollectorInterface
*/
public function setBudget(Budget $budget): JournalCollectorInterface;
+ /**
+ * @param Collection $categories
+ *
+ * @return JournalCollectorInterface
+ */
+ public function setCategories(Collection $categories): JournalCollectorInterface;
+
/**
* @param Category $category
*
diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php
index f8d9882e28..d38be5f4db 100644
--- a/app/Http/Controllers/Chart/CategoryController.php
+++ b/app/Http/Controllers/Chart/CategoryController.php
@@ -16,10 +16,13 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
+use FireflyIII\Helpers\Collector\JournalCollector;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
+use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
@@ -48,7 +51,6 @@ class CategoryController extends Controller
$this->generator = app(CategoryChartGeneratorInterface::class);
}
-
/**
* 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);
}
+ /**
+ * @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 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 Category $category
diff --git a/public/js/ff/charts.js b/public/js/ff/charts.js
index 7201e1f0cb..07ea8ca68c 100644
--- a/public/js/ff/charts.js
+++ b/public/js/ff/charts.js
@@ -8,6 +8,8 @@
/* globals $, Chart, currencySymbol,mon_decimal_point ,accounting, mon_thousands_sep, frac_digits */
+var allCharts = {};
+
/*
Make some colours:
*/
@@ -29,7 +31,6 @@ var colourSet = [
[240, 98, 146],
[0, 121, 107],
[194, 24, 91]
-
];
var fillColors = [];
@@ -234,6 +235,11 @@ function lineChart(URL, container, options) {
function areaChart(URL, container, options) {
"use strict";
+ if ($('#' + container).length === 0) {
+ console.log('No container called ' + container + ' was found.');
+ return;
+ }
+
$.getJSON(URL).done(function (data) {
var ctx = document.getElementById(container).getContext("2d");
var newData = {};
@@ -358,14 +364,30 @@ function stackedColumnChart(URL, container, options) {
function pieChart(URL, container, options) {
"use strict";
+ if ($('#' + container).length === 0) {
+ console.log('No container called ' + container + ' was found.');
+ return;
+ }
+
$.getJSON(URL).done(function (data) {
- var ctx = document.getElementById(container).getContext("2d");
- new Chart(ctx, {
- type: 'pie',
- data: data,
- options: defaultPieOptions
- });
+ 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");
+ allCharts[container] = new Chart(ctx, {
+ type: 'pie',
+ data: data,
+ options: defaultPieOptions
+ });
+ }
+
}).fail(function () {
$('#' + container).addClass('general-chart-error');
diff --git a/public/js/ff/index.js b/public/js/ff/index.js
index c714f83ac7..a6a7e5d795 100644
--- a/public/js/ff/index.js
+++ b/public/js/ff/index.js
@@ -1,4 +1,4 @@
-/* globals $, columnChart,showTour, Tour, google, lineChart, pieChart, stackedColumnChart, areaChart */
+ /* globals $, columnChart,showTour, Tour, google, lineChart, pieChart, stackedColumnChart, areaChart */
$(function () {
"use strict";
diff --git a/public/js/ff/reports/category/all.js b/public/js/ff/reports/category/all.js
new file mode 100644
index 0000000000..25a412d1c5
--- /dev/null
+++ b/public/js/ff/reports/category/all.js
@@ -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.
+ */
+
diff --git a/public/js/ff/reports/category/month.js b/public/js/ff/reports/category/month.js
new file mode 100644
index 0000000000..250ca75b53
--- /dev/null
+++ b/public/js/ff/reports/category/month.js
@@ -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);
+}
\ No newline at end of file
diff --git a/resources/views/reports/category/month.twig b/resources/views/reports/category/month.twig
index 4864dc3ca6..71ac4b5921 100644
--- a/resources/views/reports/category/month.twig
+++ b/resources/views/reports/category/month.twig
@@ -8,14 +8,135 @@
- Summary here. Accounts and categories involved. Summary of in/out
+
+
+
+
+
+
+ {{ 'name'|_ }} |
+ {{ 'earned'|_ }} |
+ {{ 'spent'|_ }} |
+
+
+
+ {% for account in accounts %}
+
+
+ {{ account.name }}
+ |
+
+ {% if accountSummary[account.id] %}
+ {{ accountSummary[account.id].earned|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
+ |
+
+ {% if accountSummary[account.id] %}
+ {{ accountSummary[account.id].spent|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'name'|_ }} |
+ {{ 'earned'|_ }} |
+ {{ 'spent'|_ }} |
+
+
+
+ {% for category in categories %}
+
+
+ {{ category.name }}
+ |
+
+ {% if categorySummary[category.id] %}
+ {{ categorySummary[category.id].earned|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
+ |
+
+ {% if categorySummary[category.id] %}
+ {{ categorySummary[category.id].spent|formatAmount }}
+ {% else %}
+ {{ 0|formatAmount }}
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+
+
-
- Pie chart with spending (aka all withdrawals in category). Optional checkbox to include all other transactions.
+ {% if categories.count > 1 %}
+
+
+
+
+
+
+
+
-
- Pie chart with income (aka all deposits in category). Optional checkbox to include all other transactions (for comparison).
+
+
+
+
+
+
+
+
+ {% endif %}
+ {% if accounts.count > 1 %}
+
+
+ {% endif %}
+ {#Pie chart with income (aka all deposits in category). Optional checkbox to include all other transactions (for comparison).#}
@@ -59,6 +180,23 @@
{% endblock %}
{% block scripts %}
+
+
+
+
+
+
+
+
+
{% endblock %}
{% block styles %}
diff --git a/routes/web.php b/routes/web.php
index 464999178f..6be7a49bc5 100755
--- a/routes/web.php
+++ b/routes/web.php
@@ -204,11 +204,14 @@ Route::group(
// categories:
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/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
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:
Route::get('/chart/piggy-bank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);