diff --git a/app/Generator/Chart/Category/CategoryChartGenerator.php b/app/Generator/Chart/Category/CategoryChartGenerator.php index 16c04a48bd..3c2698c5b7 100644 --- a/app/Generator/Chart/Category/CategoryChartGenerator.php +++ b/app/Generator/Chart/Category/CategoryChartGenerator.php @@ -40,5 +40,13 @@ interface CategoryChartGenerator * * @return array */ - public function year(Collection $categories, Collection $entries); + public function spentInYear(Collection $categories, Collection $entries); + + /** + * @param Collection $categories + * @param Collection $entries + * + * @return array + */ + public function earnedInYear(Collection $categories, Collection $entries); } diff --git a/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php b/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php index 42e17d875c..52e0b530d6 100644 --- a/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php +++ b/app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php @@ -93,7 +93,41 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator * * @return array */ - public function year(Collection $categories, Collection $entries) + public function spentInYear(Collection $categories, Collection $entries) + { + + // language: + $language = Preferences::get('language', 'en')->data; + $format = Config::get('firefly.month.' . $language); + + $data = [ + 'count' => 0, + 'labels' => [], + 'datasets' => [], + ]; + + foreach ($categories as $category) { + $data['labels'][] = $category->name; + } + + foreach ($entries as $entry) { + $date = $entry[0]->formatLocalized($format); + array_shift($entry); + $data['count']++; + $data['datasets'][] = ['label' => $date, 'data' => $entry]; + } + + return $data; + + } + + /** + * @param Collection $categories + * @param Collection $entries + * + * @return array + */ + public function earnedInYear(Collection $categories, Collection $entries) { // language: diff --git a/app/Generator/Chart/Category/GoogleCategoryChartGenerator.php b/app/Generator/Chart/Category/GoogleCategoryChartGenerator.php index 476f90c998..5ce9fe35da 100644 --- a/app/Generator/Chart/Category/GoogleCategoryChartGenerator.php +++ b/app/Generator/Chart/Category/GoogleCategoryChartGenerator.php @@ -86,7 +86,31 @@ class GoogleCategoryChartGenerator implements CategoryChartGenerator * * @return array */ - public function year(Collection $categories, Collection $entries) + public function spentInYear(Collection $categories, Collection $entries) + { + $chart = new GChart; + + $chart->addColumn(trans('firefly.month'), 'date'); + foreach ($categories as $category) { + $chart->addColumn($category->name, 'number'); + } + /** @var array $entry */ + foreach ($entries as $entry) { + $chart->addRowArray($entry); + } + $chart->generate(); + + return $chart->getData(); + + } + + /** + * @param Collection $categories + * @param Collection $entries + * + * @return array + */ + public function earnedInYear(Collection $categories, Collection $entries) { $chart = new GChart; diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php index f1fde920dc..2a190b2f51 100644 --- a/app/Http/Controllers/Chart/CategoryController.php +++ b/app/Http/Controllers/Chart/CategoryController.php @@ -46,11 +46,10 @@ class CategoryController extends Controller public function all(CategoryRepositoryInterface $repository, Category $category) { // oldest transaction in category: - $start = $repository->getFirstActivityDate($category); - $range = Preferences::get('viewRange', '1M')->data; - $start = Navigation::startOfPeriod($start, $range); - $end = new Carbon; - + $start = $repository->getFirstActivityDate($category); + $range = Preferences::get('viewRange', '1M')->data; + $start = Navigation::startOfPeriod($start, $range); + $end = new Carbon; $entries = new Collection; @@ -170,7 +169,7 @@ class CategoryController extends Controller * * @return \Symfony\Component\HttpFoundation\Response */ - public function year(CategoryRepositoryInterface $repository, $year, $shared = false) + public function spentInYear(CategoryRepositoryInterface $repository, $year, $shared = false) { $start = new Carbon($year . '-01-01'); $end = new Carbon($year . '-12-31'); @@ -179,14 +178,23 @@ class CategoryController extends Controller $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('category'); - $cache->addProperty('year'); + $cache->addProperty('spent-in-year'); if ($cache->has()) { return Response::json($cache->get()); // @codeCoverageIgnore } - $shared = $shared == 'shared' ? true : false; - $categories = $repository->getCategories(); - $entries = new Collection; + $shared = $shared == 'shared' ? true : false; + $allCategories = $repository->getCategories(); + $entries = new Collection; + $categories = new Collection; + + // filter by checking the entire year first: + foreach ($allCategories as $category) { + $spent = $repository->spentInPeriodCorrected($category, $start, $end, $shared); + if ($spent < 0) { + $categories->push($category); + } + } while ($start < $end) { $month = clone $start; // month is the current end of the period @@ -195,14 +203,83 @@ class CategoryController extends Controller foreach ($categories as $category) { // each budget, fill the row $spent = $repository->spentInPeriodCorrected($category, $start, $month, $shared); - $row[] = $spent; + if ($spent < 0) { + $spent = $spent * -1; + $row[] = $spent; + } else { + $row[] = 0; + } + } $entries->push($row); $start->addMonth(); } - $data = $this->generator->year($categories, $entries); + $data = $this->generator->spentInYear($categories, $entries); + $cache->store($data); + + return Response::json($data); + } + + /** + * This chart will only show income. + * + * @param CategoryRepositoryInterface $repository + * @param $year + * @param bool $shared + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function earnedInYear(CategoryRepositoryInterface $repository, $year, $shared = false) + { + $start = new Carbon($year . '-01-01'); + $end = new Carbon($year . '-12-31'); + + $cache = new CacheProperties; // chart properties for cache: + $cache->addProperty($start); + $cache->addProperty($end); + $cache->addProperty('category'); + $cache->addProperty('earned-in-year'); + if ($cache->has()) { + return Response::json($cache->get()); // @codeCoverageIgnore + } + + $shared = $shared == 'shared' ? true : false; + $allCategories = $repository->getCategories(); + $allEntries = new Collection; + $categories = new Collection; + + // filter by checking the entire year first: + foreach ($allCategories as $category) { + $spent = $repository->spentInPeriodCorrected($category, $start, $end, $shared); + if ($spent > 0) { + $categories->push($category); + } + } + + + while ($start < $end) { + $month = clone $start; // month is the current end of the period + $month->endOfMonth(); + $row = [clone $start]; // make a row: + + foreach ($categories as $category) { // each budget, fill the row + $spent = $repository->spentInPeriodCorrected($category, $start, $month, $shared); + if ($spent > 0) { + $row[] = $spent; + } else { + $row[] = 0; + } + + } + $allEntries->push($row); + + $start->addMonth(); + } + + + $data = $this->generator->earnedInYear($categories, $allEntries); $cache->store($data); return Response::json($data); diff --git a/app/Http/routes.php b/app/Http/routes.php index 17307916dc..fcdfae5800 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -300,7 +300,8 @@ Route::group( // categories: Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']); - Route::get('/chart/category/year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']); + Route::get('/chart/category/spent-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@spentInYear'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']); + Route::get('/chart/category/earned-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@earnedInYear'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']); Route::get('/chart/category/{category}/month', ['uses' => 'Chart\CategoryController@month']); // should be period. Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index c60864d473..d7f77edcff 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -315,7 +315,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn */ public function spentInPeriodCorrected(Budget $budget, Carbon $start, Carbon $end, $shared = true) { - return $this->spentInPeriod($budget, $start, $end, $shared); + return $this->balanceInPeriod($budget, $start, $end, $shared); } /** diff --git a/app/Repositories/Category/CategoryRepository.php b/app/Repositories/Category/CategoryRepository.php index 3686fbc581..c7590d55d7 100644 --- a/app/Repositories/Category/CategoryRepository.php +++ b/app/Repositories/Category/CategoryRepository.php @@ -185,7 +185,7 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito */ public function spentInPeriodCorrected(Category $category, Carbon $start, Carbon $end, $shared = false) { - return $this->spentInPeriod($category, $start, $end, $shared); + return $this->balanceInPeriod($category, $start, $end, $shared); } /** diff --git a/app/Repositories/Shared/ComponentRepository.php b/app/Repositories/Shared/ComponentRepository.php index c97019880a..a2b3705db8 100644 --- a/app/Repositories/Shared/ComponentRepository.php +++ b/app/Repositories/Shared/ComponentRepository.php @@ -24,7 +24,7 @@ class ComponentRepository * * @return string */ - protected function spentInPeriod($object, Carbon $start, Carbon $end, $shared = false) + protected function balanceInPeriod($object, Carbon $start, Carbon $end, $shared = false) { $cache = new CacheProperties; // we must cache this. $cache->addProperty($object->id); @@ -45,14 +45,13 @@ class ComponentRepository // do something else, SEE budgets. // get all journals in this month where the asset account is NOT shared. $sum = $object->transactionjournals()->before($end)->after($start) - ->transactionTypes(['Withdrawal']) ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->leftJoin( 'account_meta', function (JoinClause $join) { $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); } - )->where('account_meta.data', '!=', '"sharedAsset"')->get(['transaction_journals.*'])->sum('amount'); + )->where('account_meta.data', '!=', '"sharedAsset"')->get(['transaction_journals.*'])->sum('correct_amount'); } $cache->store($sum); diff --git a/public/js/reports.js b/public/js/reports.js index 0c63642830..7652eaf40a 100644 --- a/public/js/reports.js +++ b/public/js/reports.js @@ -18,7 +18,8 @@ function drawChart() { } if (typeof stackedColumnChart !== 'undefined' && typeof year !== 'undefined' && typeof month === 'undefined') { stackedColumnChart('chart/budget/year/' + year + shared, 'budgets'); - stackedColumnChart('chart/category/year/' + year + shared, 'categories'); + stackedColumnChart('chart/category/spent-in-year/' + year + shared, 'categories-spent-in-year'); + stackedColumnChart('chart/category/earned-in-year/' + year + shared, 'categories-earned-in-year'); } if (typeof lineChart !== 'undefined' && typeof month !== 'undefined') { lineChart('/chart/account/month/' + year + '/' + month + shared, 'account-balances-chart'); diff --git a/resources/lang/en/firefly.php b/resources/lang/en/firefly.php index 26a67e6de9..b386e977a4 100644 --- a/resources/lang/en/firefly.php +++ b/resources/lang/en/firefly.php @@ -396,6 +396,8 @@ return [ 'hideTheRest' => 'Show only the top :number', 'sum_of_year' => 'Sum of year', 'average_of_year' => 'Average of year', + 'categories_earned_in_year' => 'Categories (by earnings)', + 'categories_spent_in_year' => 'Categories (by spendings)', // charts: 'dayOfMonth' => 'Day of the month', diff --git a/resources/lang/nl/firefly.php b/resources/lang/nl/firefly.php index 82f115da14..e06fe78ad1 100644 --- a/resources/lang/nl/firefly.php +++ b/resources/lang/nl/firefly.php @@ -404,6 +404,8 @@ return [ 'topX' => 'top :number', 'showTheRest' => 'Laat alles zien', 'hideTheRest' => 'Laat alleen de top :number zien', + 'categories_earned_in_year' => 'Categorieën (inkomsten)', + 'categories_spent_in_year' => 'Categorieën (uitgaven)', // charts: 'dayOfMonth' => 'Dag vd maand', diff --git a/resources/twig/reports/year.twig b/resources/twig/reports/year.twig index 28f8371b6b..0d543bc54a 100644 --- a/resources/twig/reports/year.twig +++ b/resources/twig/reports/year.twig @@ -56,19 +56,38 @@
-

{{ 'categories'|_ }}

+

{{ 'categories_spent_in_year'|_ }}

{% if Config.get('firefly.chart') == 'google' %} -
+
{% endif %} {% if Config.get('firefly.chart') == 'chartjs' %} - + {% endif %}
+ +
+
+
+
+

{{ 'categories_earned_in_year'|_ }}

+
+
+ {% if Config.get('firefly.chart') == 'google' %} +
+ {% endif %} + {% if Config.get('firefly.chart') == 'chartjs' %} + + {% endif %} +
+
+
+
+