diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php index d16dd1efd4..95934e3432 100644 --- a/app/Http/Controllers/Chart/CategoryController.php +++ b/app/Http/Controllers/Chart/CategoryController.php @@ -274,8 +274,6 @@ class CategoryController extends Controller /** * Chart for period for transactions without a category. * - * TODO this chart is not multi-currency aware. - * * @param Collection $accounts * @param Carbon $start * @param Carbon $end @@ -290,35 +288,156 @@ class CategoryController extends Controller $cache->addProperty('chart.category.period.no-cat'); $cache->addProperty($accounts->pluck('id')->toArray()); if ($cache->has()) { - return response()->json($cache->get()); // @codeCoverageIgnore + // return response()->json($cache->get()); // @codeCoverageIgnore } /** @var NoCategoryRepositoryInterface $noCatRepository */ $noCatRepository = app(NoCategoryRepositoryInterface::class); - $expenses = $noCatRepository->periodExpensesNoCategory($accounts, $start, $end); - $income = $noCatRepository->periodIncomeNoCategory($accounts, $start, $end); - $periods = app('navigation')->listOfPeriods($start, $end); - $chartData = [ - [ - 'label' => (string)trans('firefly.spent'), + // this gives us all currencies + $expenses = $noCatRepository->listExpenses($start, $end); + $income = $noCatRepository->listIncome($start, $end); + $currencies = array_unique(array_merge(array_keys($income), array_keys($expenses))); + $periods = app('navigation')->listOfPeriods($start, $end); + $format = app('navigation')->preferredCarbonLocalizedFormat($start, $end); + $chartData = []; + // make empty data array: + // double foreach (bad) to make empty array: + foreach ($currencies as $currencyId) { + $currencyInfo = $expenses[$currencyId] ?? $income[$currencyId]; + $outKey = sprintf('%d-out', $currencyId); + $inKey = sprintf('%d-in', $currencyId); + + $chartData[$outKey] + = [ + 'label' => sprintf('%s (%s)', (string)trans('firefly.spent'), $currencyInfo['currency_name']), 'entries' => [], 'type' => 'bar', 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red - ], - [ - 'label' => (string)trans('firefly.earned'), + ]; + + $chartData[$inKey] + = [ + 'label' => sprintf('%s (%s)', (string)trans('firefly.earned'), $currencyInfo['currency_name']), 'entries' => [], 'type' => 'bar', 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green - ], - [ - 'label' => (string)trans('firefly.sum'), - 'entries' => [], - 'type' => 'line', - 'fill' => false, - ], - ]; + ]; + + // loop empty periods: + foreach (array_keys($periods) as $period) { + $label = $periods[$period]; + $chartData[$outKey]['entries'][$label] = '0'; + $chartData[$inKey]['entries'][$label] = '0'; + } + // loop income and expenses: + $outSet = $expenses[$currencyId] ?? ['transaction_journals' => []]; + foreach ($outSet['transaction_journals'] as $journal) { + $date = $journal['date']->formatLocalized($format); + $chartData[$outKey]['entries'][$date] = bcadd($journal['amount'], $chartData[$outKey]['entries'][$date]); + } + + $inSet = $income[$currencyId] ?? ['transaction_journals' => []]; + foreach ($inSet['transaction_journals'] as $journal) { + $date = $journal['date']->formatLocalized($format); + $chartData[$inKey]['entries'][$date] = bcadd($journal['amount'], $chartData[$inKey]['entries'][$date]); + } + } + $data = $this->generator->multiSet($chartData); + $cache->store($data); + + return response()->json($data); + var_dump($chartData); + var_dump(array_values($chartData)); + exit; + + + $format = app('navigation')->preferredCarbonLocalizedFormat($start, $end); + $chartData = []; + + // double foreach (bad) to make empty array: + foreach ($currencies as $currencyId) { + $currencyInfo = $expenses[$currencyId] ?? $income[$currencyId]; + + $spentArray + = [ + 'label' => sprintf('%s (%s)', (string)trans('firefly.spent'), $currencyInfo['currency_name']), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red + ]; + $incomeArray + = [ + 'label' => sprintf('%s (%s)', (string)trans('firefly.earned'), $currencyInfo['currency_name']), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green + ]; + + foreach (array_keys($periods) as $period) { + $label = $periods[$period]; + $spentArray['entries'][$label] = '0'; + $incomeArray['entries'][$label] = '0'; + + // then loop income and then loop expenses, maybe? + $currencyExpenses = $expenses[$currencyId] ?? ['transaction_journals' => []]; + foreach ($currencyExpenses['transaction_journals'] as $row) { + + } + } + $chartData[] = $spentArray; + $chartData[] = $incomeArray; + } + var_dump($chartData); + exit; + + + foreach ($currencies as $currencyId) { + $currencyInfo = $expenses[$currencyId] ?? $income[$currencyId]; + // loop expenses[$currencyId], if set + $spentArray + = [ + 'label' => sprintf('%s (%s)', (string)trans('firefly.spent'), $currencyInfo['currency_name']), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red + ]; + + $current = $expenses[$currencyId] ?? ['transaction_journals' => []]; + foreach ($current['transaction_journals'] as $row) { + $thisPeriod = $row['date']->formatLocalized($format); + $spentArray['entries'][$thisPeriod] = $spentArray['entries'][$thisPeriod] ?? '0'; + $spentArray['entries'][$thisPeriod] = bcadd($spentArray['entries'][$thisPeriod], $row['amount']); + } + $chartData[] = $spentArray; + + // loop income[$currencyId], if set + $incomeArray + = [ + 'label' => sprintf('%s (%s)', (string)trans('firefly.earned'), $currencyInfo['currency_name']), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green + ]; + + $current = $income[$currencyId] ?? ['transaction_journals' => []]; + foreach ($current['transaction_journals'] as $row) { + $thisPeriod = $row['date']->formatLocalized($format); + $incomeArray['entries'][$thisPeriod] = $incomeArray['entries'][$thisPeriod] ?? '0'; + $incomeArray['entries'][$thisPeriod] = bcadd($incomeArray['entries'][$thisPeriod], $row['amount']); + } + $chartData[] = $incomeArray; + + // $chartData[] = [ + // 'label' => sprintf('%s (%s)', (string)trans('firefly.earned'), $currencyInfo['currency_name']), + // 'entries' => [], + // 'type' => 'bar', + // 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green + // ]; + } + echo '
';
+        print_r($chartData);
+        exit;
 
         foreach (array_keys($periods) as $period) {
             $label                           = $periods[$period];
diff --git a/app/Http/Controllers/Report/CategoryController.php b/app/Http/Controllers/Report/CategoryController.php
index 8d8e5cbd1e..3a81a8a2fa 100644
--- a/app/Http/Controllers/Report/CategoryController.php
+++ b/app/Http/Controllers/Report/CategoryController.php
@@ -58,7 +58,7 @@ class CategoryController extends Controller
         $cache->addProperty('category-period-expenses-report');
         $cache->addProperty($accounts->pluck('id')->toArray());
         if ($cache->has()) {
-            return $cache->get(); // @codeCoverageIgnore
+            //return $cache->get(); // @codeCoverageIgnore
         }
         /** @var CategoryRepositoryInterface $repository */
         $repository = app(CategoryRepositoryInterface::class);
@@ -66,9 +66,14 @@ class CategoryController extends Controller
         /** @var OperationsRepositoryInterface $opsRepository */
         $opsRepository = app(OperationsRepositoryInterface::class);
 
+        /** @var NoCategoryRepositoryInterface $noCatRepos */
+        $noCatRepos = app(NoCategoryRepositoryInterface::class);
+
+        $periods    = app('navigation')->listOfPeriods($start, $end);
+        $data       = [];
         $categories = $repository->getCategories();
         $data       = $opsRepository->periodExpenses($categories, $accounts, $start, $end);
-        $data[0]    = $opsRepository->periodExpensesNoCategory($accounts, $start, $end);
+        $data[0]    = $noCatRepos->periodExpensesNoCategory($accounts, $start, $end);
         $report     = $this->filterPeriodReport($data);
 
         // depending on the carbon format (a reliable way to determine the general date difference)
@@ -82,7 +87,7 @@ class CategoryController extends Controller
             $start->startOfMonth();
         }
 
-        $periods    = app('navigation')->listOfPeriods($start, $end);
+
         try {
             $result = view('reports.partials.category-period', compact('report', 'periods'))->render();
             // @codeCoverageIgnoreStart
@@ -143,7 +148,7 @@ class CategoryController extends Controller
             $start->startOfMonth();
         }
 
-        $periods    = app('navigation')->listOfPeriods($start, $end);
+        $periods = app('navigation')->listOfPeriods($start, $end);
         try {
             $result = view('reports.partials.category-period', compact('report', 'periods'))->render();
             // @codeCoverageIgnoreStart
@@ -193,8 +198,8 @@ class CategoryController extends Controller
         ];
         /** @var Category $category */
         foreach ($categories as $category) {
-            $spent      = $opsRepository->spentInPeriod($category, $accounts, $start, $end);
-            $earned     = $opsRepository->earnedInPeriod($category, $accounts, $start, $end);
+            $spent  = $opsRepository->spentInPeriod($category, $accounts, $start, $end);
+            $earned = $opsRepository->earnedInPeriod($category, $accounts, $start, $end);
             if (0 === count($spent) && 0 === count($earned)) {
                 continue;
             }
@@ -210,7 +215,7 @@ class CategoryController extends Controller
                     'currency_id'             => $currencyInfo['currency_id'],
                     'currency_code'           => $currencyInfo['currency_code'],
                     'currency_symbol'         => $currencyInfo['currency_symbol'],
-                    'currency_name'         => $currencyInfo['currency_name'],
+                    'currency_name'           => $currencyInfo['currency_name'],
                     'currency_decimal_places' => $currencyInfo['currency_decimal_places'],
                 ];
 
@@ -228,17 +233,17 @@ class CategoryController extends Controller
 
         // get sums:
         foreach ($report['categories'] as $entry) {
-            $currencyId                  = $entry['currency_id'];
-            $report['sums'][$currencyId] = $report['sums'][$currencyId] ?? [
-                    'spent'                     => '0',
-                    'earned'                     => '0',
+            $currencyId                            = $entry['currency_id'];
+            $report['sums'][$currencyId]           = $report['sums'][$currencyId] ?? [
+                    'spent'                   => '0',
+                    'earned'                  => '0',
                     'currency_id'             => $entry['currency_id'],
                     'currency_code'           => $entry['currency_code'],
                     'currency_symbol'         => $entry['currency_symbol'],
-                    'currency_name'         => $entry['currency_name'],
+                    'currency_name'           => $entry['currency_name'],
                     'cyrrency_decimal_places' => $entry['currency_decimal_places'],
                 ];
-            $report['sums'][$currencyId]['spent'] = bcadd($report['sums'][$currencyId]['spent'], $entry['spent']);
+            $report['sums'][$currencyId]['spent']  = bcadd($report['sums'][$currencyId]['spent'], $entry['spent']);
             $report['sums'][$currencyId]['earned'] = bcadd($report['sums'][$currencyId]['earned'], $entry['earned']);
         }
 
diff --git a/app/Repositories/Category/NoCategoryRepository.php b/app/Repositories/Category/NoCategoryRepository.php
index 0ab5a02ba2..22dda6963b 100644
--- a/app/Repositories/Category/NoCategoryRepository.php
+++ b/app/Repositories/Category/NoCategoryRepository.php
@@ -51,6 +51,96 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
         }
     }
 
+    /**
+     * This method returns a list of all the withdrawal transaction journals (as arrays) set in that period
+     * which have no category set to them. It's grouped per currency, with as few details in the array
+     * as possible. Amounts are always negative.
+     *
+     * @param Carbon          $start
+     * @param Carbon          $end
+     * @param Collection|null $accounts
+     *
+     * @return array
+     */
+    public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array
+    {
+        /** @var GroupCollectorInterface $collector */
+        $collector = app(GroupCollectorInterface::class);
+        $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->withoutCategory();
+        if (null !== $accounts && $accounts->count() > 0) {
+            $collector->setAccounts($accounts);
+        }
+        $journals = $collector->getExtractedJournals();
+        $array    = [];
+
+        foreach ($journals as $journal) {
+            $currencyId         = (int)$journal['currency_id'];
+            $array[$currencyId] = $array[$currencyId] ?? [
+                    'transaction_journals'    => [],
+                    'currency_id'             => $currencyId,
+                    'currency_name'           => $journal['currency_name'],
+                    'currency_symbol'         => $journal['currency_symbol'],
+                    'currency_code'           => $journal['currency_code'],
+                    'currency_decimal_places' => $journal['currency_decimal_places'],
+                ];
+            // add journal to array:
+            // only a subset of the fields.
+            $journalId                                              = (int)$journal['transaction_journal_id'];
+            $array[$currencyId]['transaction_journals'][$journalId] = [
+                'amount' => app('steam')->negative($journal['amount']),
+                'date'   => $journal['date'],
+            ];
+
+        }
+
+        return $array;
+    }
+
+    /**
+     * This method returns a list of all the deposit transaction journals (as arrays) set in that period
+     * which have no category set to them. It's grouped per currency, with as few details in the array
+     * as possible. Amounts are always positive.
+     *
+     * @param Carbon          $start
+     * @param Carbon          $end
+     * @param Collection|null $accounts
+     *
+     * @return array
+     */
+    public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array
+    {
+        /** @var GroupCollectorInterface $collector */
+        $collector = app(GroupCollectorInterface::class);
+        $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->withoutCategory();
+        if (null !== $accounts && $accounts->count() > 0) {
+            $collector->setAccounts($accounts);
+        }
+        $journals = $collector->getExtractedJournals();
+        $array    = [];
+
+        foreach ($journals as $journal) {
+            $currencyId         = (int)$journal['currency_id'];
+            $array[$currencyId] = $array[$currencyId] ?? [
+                    'transaction_journals'    => [],
+                    'currency_id'             => $currencyId,
+                    'currency_name'           => $journal['currency_name'],
+                    'currency_symbol'         => $journal['currency_symbol'],
+                    'currency_code'           => $journal['currency_code'],
+                    'currency_decimal_places' => $journal['currency_decimal_places'],
+                ];
+            // add journal to array:
+            // only a subset of the fields.
+            $journalId                                              = (int)$journal['transaction_journal_id'];
+            $array[$currencyId]['transaction_journals'][$journalId] = [
+                'amount' => app('steam')->positive($journal['amount']),
+                'date'   => $journal['date'],
+            ];
+
+        }
+
+        return $array;
+    }
+
     /**
      * @param Collection $accounts
      * @param Carbon     $start
@@ -192,7 +282,6 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
     {
         /** @var GroupCollectorInterface $collector */
         $collector = app(GroupCollectorInterface::class);
-
         $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->withoutCategory();
 
         if (null !== $accounts && $accounts->count() > 0) {
@@ -216,4 +305,41 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
 
         return $array;
     }
+
+    /**
+     * Sum of withdrawal journals in period without a category, grouped per currency. Amounts are always negative.
+     *
+     * @param Carbon          $start
+     * @param Carbon          $end
+     * @param Collection|null $accounts
+     *
+     * @return array
+     */
+    public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array
+    {
+        /** @var GroupCollectorInterface $collector */
+        $collector = app(GroupCollectorInterface::class);
+        $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->withoutCategory();
+
+        if (null !== $accounts && $accounts->count() > 0) {
+            $collector->setAccounts($accounts);
+        }
+        $journals = $collector->getExtractedJournals();
+        $array    = [];
+
+        foreach ($journals as $journal) {
+            $currencyId                = (int)$journal['currency_id'];
+            $array[$currencyId]        = $array[$currencyId] ?? [
+                    'sum'                     => '0',
+                    'currency_id'             => $currencyId,
+                    'currency_name'           => $journal['currency_name'],
+                    'currency_symbol'         => $journal['currency_symbol'],
+                    'currency_code'           => $journal['currency_code'],
+                    'currency_decimal_places' => $journal['currency_decimal_places'],
+                ];
+            $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount']));
+        }
+
+        return $array;
+    }
 }
\ No newline at end of file
diff --git a/app/Repositories/Category/NoCategoryRepositoryInterface.php b/app/Repositories/Category/NoCategoryRepositoryInterface.php
index eee7a07eb6..2611cbfee3 100644
--- a/app/Repositories/Category/NoCategoryRepositoryInterface.php
+++ b/app/Repositories/Category/NoCategoryRepositoryInterface.php
@@ -58,7 +58,7 @@ interface NoCategoryRepositoryInterface
      *
      * @return array
      */
-    //public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
+    public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
 
     /**
      * Sum of withdrawal journals in period without a category, grouped per currency. Amounts are always negative.
@@ -69,7 +69,7 @@ interface NoCategoryRepositoryInterface
      *
      * @return array
      */
-    //public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
+    public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
 
     /**
      * TODO not multi-currency
@@ -114,5 +114,18 @@ interface NoCategoryRepositoryInterface
      */
     public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
 
+    /**
+     * This method returns a list of all the deposit transaction journals (as arrays) set in that period
+     * which have no category set to them. It's grouped per currency, with as few details in the array
+     * as possible. Amounts are always positive.
+     *
+     * @param Carbon          $start
+     * @param Carbon          $end
+     * @param Collection|null $accounts
+     *
+     * @return array
+     */
+    public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
+
 
 }
\ No newline at end of file
diff --git a/app/Repositories/Category/OperationsRepository.php b/app/Repositories/Category/OperationsRepository.php
index 233d42d71b..04fb867d23 100644
--- a/app/Repositories/Category/OperationsRepository.php
+++ b/app/Repositories/Category/OperationsRepository.php
@@ -31,6 +31,7 @@ use FireflyIII\Models\TransactionType;
 use FireflyIII\User;
 use Illuminate\Support\Collection;
 use Log;
+use Navigation;
 
 /**
  *
diff --git a/routes/web.php b/routes/web.php
index 61efe0ceae..25cb662a45 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -353,15 +353,13 @@ Route::group(
  */
 Route::group(
     ['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers\Chart', 'prefix' => 'chart/category', 'as' => 'chart.category.'],
-    function () {
+    static function () {
 
         Route::get('frontpage', ['uses' => 'CategoryController@frontPage', 'as' => 'frontpage']);
         Route::get('period/{category}', ['uses' => 'CategoryController@currentPeriod', 'as' => 'current']);
         Route::get('period/{category}/{date}', ['uses' => 'CategoryController@specificPeriod', 'as' => 'specific']);
         Route::get('all/{category}', ['uses' => 'CategoryController@all', 'as' => 'all']);
-        Route::get(
-            'report-period/0/{accountList}/{start_date}/{end_date}', ['uses' => 'CategoryController@reportPeriodNoCategory', 'as' => 'period.no-category']
-        );
+        Route::get('report-period/0/{accountList}/{start_date}/{end_date}', ['uses' => 'CategoryController@reportPeriodNoCategory', 'as' => 'period.no-category']);
         Route::get('report-period/{category}/{accountList}/{start_date}/{end_date}', ['uses' => 'CategoryController@reportPeriod', 'as' => 'period']);
 
         // these charts are used in reports (category reports):