diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index 49e3c91119..487357342b 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -262,7 +262,7 @@ class AccountController extends Controller $cache->addProperty($end); $cache->addProperty('chart.account.expense-category'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } /** @var GroupCollectorInterface $collector */ diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index b83692f914..7976d53201 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -498,7 +498,7 @@ class BudgetController extends Controller $cache->addProperty($currency->id); $cache->addProperty('chart.budget.period'); if ($cache->has()) { - // return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } $titleFormat = app('navigation')->preferredCarbonLocalizedFormat($start, $end); $preferredRange = app('navigation')->preferredRangeFormat($start, $end); diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php index 657a982c54..be4142a45d 100644 --- a/app/Http/Controllers/Chart/CategoryController.php +++ b/app/Http/Controllers/Chart/CategoryController.php @@ -26,13 +26,12 @@ use Carbon\Carbon; use Exception; use FireflyIII\Generator\Chart\Basic\GeneratorInterface; use FireflyIII\Http\Controllers\Controller; -use FireflyIII\Models\AccountType; use FireflyIII\Models\Category; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface; use FireflyIII\Repositories\Category\OperationsRepositoryInterface; use FireflyIII\Support\CacheProperties; +use FireflyIII\Support\Chart\Category\FrontpageChartGenerator; use FireflyIII\Support\Chart\Category\WholePeriodChartGenerator; use FireflyIII\Support\Http\Controllers\AugumentData; use FireflyIII\Support\Http\Controllers\ChartGeneration; @@ -117,96 +116,11 @@ class CategoryController extends Controller // return response()->json($cache->get()); // @codeCoverageIgnore } - // currency repos: - /** @var CategoryRepositoryInterface $repository */ - $repository = app(CategoryRepositoryInterface::class); + $frontPageGenerator = new FrontpageChartGenerator($start, $end); - /** @var AccountRepositoryInterface $accountRepository */ - $accountRepository = app(AccountRepositoryInterface::class); - /** @var OperationsRepositoryInterface $opsRepository */ - $opsRepository = app(OperationsRepositoryInterface::class); - - /** @var NoCategoryRepositoryInterface $noCatRepository */ - $noCatRepository = app(NoCategoryRepositoryInterface::class); - - $chartData = []; - $currencies = []; - $tempData = []; - $categories = $repository->getCategories(); - $accounts = $accountRepository->getAccountsByType( - [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT] - ); - - /** @var Category $category */ - foreach ($categories as $category) { - $collection = new Collection([$category]); - $spent = $opsRepository->sumExpenses($start, $end, $accounts, $collection); - //$spentArray = $opsRepository->spentInPeriodPerCurrency(new Collection([$category]), $accounts, $start, $end); - foreach ($spent as $currency) { - $currencyId = $currency['currency_id']; - $currencies[$currencyId] = $currencies[$currencyId] ?? [ - 'currency_id' => $currencyId, - 'currency_name' => $currency['currency_name'], - 'currency_symbol' => $currency['currency_symbol'], - 'currency_code' => $currency['currency_code'], - 'currency_decimal_places' => $currency['currency_decimal_places'], - ]; - $tempData[] = [ - 'name' => $category->name, - 'sum' => $currency['sum'], - 'sum_float' => round($currency['sum'], $currency['currency_decimal_places']), - 'currency_id' => $currencyId, - ]; - } - } - - // no category per currency: - $noCategory = $noCatRepository->sumExpenses($start, $end); - if (0 !== bccomp($noCategory[0]['sum'] ?? '0', '0')) { - - foreach ($noCategory as $currency) { - $currencyId = $currency['currency_id']; - $currencies[$currencyId] = $currencies[$currencyId] ?? [ - 'currency_id' => $currency['currency_id'], - 'currency_name' => $currency['currency_name'], - 'currency_symbol' => $currency['currency_symbol'], - 'currency_code' => $currency['currency_code'], - 'currency_decimal_places' => $currency['currency_decimal_places'], - ]; - $tempData[] = [ - 'name' => trans('firefly.no_category'), - 'sum' => $currency['sum'], - 'sum_float' => round($currency['sum'], $currency['currency_decimal_places'] ?? 2), - 'currency_id' => $currency['currency_id'], - ]; - } - } - - // sort temp array by amount. - $amounts = array_column($tempData, 'sum_float'); - array_multisort($amounts, SORT_DESC, $tempData); - - // loop all found currencies and build the data array for the chart. - /** @var array $currency */ - foreach ($currencies as $currency) { - $dataSet = [ - 'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currency['currency_name']), - 'type' => 'bar', - 'currency_symbol' => $currency['currency_symbol'], - 'entries' => $this->expandNames($tempData), - ]; - $chartData[$currency['currency_id']] = $dataSet; - } - - // loop temp data and place data in correct array: - foreach ($tempData as $entry) { - $currencyId = $entry['currency_id']; - $name = $entry['name']; - $chartData[$currencyId]['entries'][$name] = bcmul($entry['sum'], '-1'); - } - - $data = $this->generator->multiSet($chartData); + $chartData = $frontPageGenerator->generate(); + $data = $this->generator->multiSet($chartData); $cache->store($data); return response()->json($data); diff --git a/app/Http/Controllers/Chart/TransactionController.php b/app/Http/Controllers/Chart/TransactionController.php index 1792a002ed..829178f21e 100644 --- a/app/Http/Controllers/Chart/TransactionController.php +++ b/app/Http/Controllers/Chart/TransactionController.php @@ -186,7 +186,7 @@ class TransactionController extends Controller $cache->addProperty($objectType); $cache->addProperty('chart.transactions.destinations'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } @@ -252,7 +252,7 @@ class TransactionController extends Controller $cache->addProperty($objectType); $cache->addProperty('chart.transactions.sources'); if ($cache->has()) { - //return response()->json($cache->get()); // @codeCoverageIgnore + return response()->json($cache->get()); // @codeCoverageIgnore } diff --git a/app/Support/Chart/Category/FrontpageChartGenerator.php b/app/Support/Chart/Category/FrontpageChartGenerator.php new file mode 100644 index 0000000000..96c26e95e9 --- /dev/null +++ b/app/Support/Chart/Category/FrontpageChartGenerator.php @@ -0,0 +1,356 @@ +. + */ + +namespace FireflyIII\Support\Chart\Category; + +use Carbon\Carbon; +use FireflyIII\Models\AccountType; +use FireflyIII\Models\Category; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Category\CategoryRepositoryInterface; +use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface; +use FireflyIII\Repositories\Category\OperationsRepositoryInterface; +use Illuminate\Support\Collection; + +/** + * Class FrontpageChartGenerator + */ +class FrontpageChartGenerator +{ + /** @var AccountRepositoryInterface */ + private $accountRepos; + /** @var array */ + private $currencies; + /** @var Carbon */ + private $end; + /** @var NoCategoryRepositoryInterface */ + private $noCatRepos; + /** @var OperationsRepositoryInterface */ + private $opsRepos; + /** @var CategoryRepositoryInterface */ + private $repository; + /** @var Carbon */ + private $start; + + /** + * FrontpageChartGenerator constructor. + * + * @param Carbon $start + * @param Carbon $end + */ + public function __construct(Carbon $start, Carbon $end) + { + $this->currencies = []; + $this->start = $start; + $this->end = $end; + $this->repository = app(CategoryRepositoryInterface::class); + $this->accountRepos = app(AccountRepositoryInterface::class); + $this->opsRepos = app(OperationsRepositoryInterface::class); + $this->noCatRepos = app(NoCategoryRepositoryInterface::class); + + } + + /** + * @return array + */ + public function generate(): array + { + // TODO collect currencies. + $chartData = []; + $tempData = []; + $categories = $this->repository->getCategories(); + $accounts = $this->accountRepos->getAccountsByType( + [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT] + ); + + // get expenses + income per category: + $collection = []; + /** @var Category $category */ + foreach ($categories as $category) { + // get expenses + $collection[] = $this->collectExpenses($category, $accounts); + $collection[] = $this->collectIncome($category, $accounts); + } + + // collect for no-category: + $collection[] = $this->collectNoCatExpenses($accounts); + $collection[] = $this->collectNoCatIncome($accounts); + + $tempData = array_merge(...$collection); + + // sort temp array by amount. + $amounts = array_column($tempData, 'sum_float'); + array_multisort($amounts, SORT_DESC, $tempData); + + $currencyData = $this->createCurrencyGroups($tempData); + $mergedData = $this->insertValues($currencyData, $tempData); + + return $mergedData; + var_dump($currencyData); + var_dump($this->currencies); + var_dump($tempData); + exit; + // // get income: + // $income = $this->opsRepos->sumIncome($start, $end, $accounts, $collection); + // foreach ($income as $currency) { + // $currencyId = $currency['currency_id']; + // $currencies[$currencyId] = $currencies[$currencyId] ?? [ + // 'currency_id' => $currencyId, + // 'currency_name' => $currency['currency_name'], + // 'currency_symbol' => $currency['currency_symbol'], + // 'currency_code' => $currency['currency_code'], + // 'currency_decimal_places' => $currency['currency_decimal_places'], + // ]; + // $tempData[] = [ + // 'name' => $category->name, + // 'sum' => $currency['sum'], + // 'sum_float' => round($currency['sum'], $currency['currency_decimal_places']), + // 'currency_id' => $currencyId, + // ]; + // } + // + // // income + expense no category per currency: + // $noCatExp + // = $this->noCatRepos->sumExpenses($start, $end); + // $noCatInc + // = $this->noCatRepos->sumIncome($start, $end); + // foreach ($noCatExp as $currency) + // { + // $currencyId + // = $currency['currency_id']; + // $currencies[$currencyId] + // = $currencies[$currencyId] ?? ['currency_id' => $currency['currency_id'], + // 'currency_name' => $currency['currency_name'], + // 'currency_symbol' => $currency['currency_symbol'], + // 'currency_code' => $currency['currency_code'], + // 'currency_decimal_places' => $currency['currency_decimal_places'],]; + // $tempData[] + // = ['name' => trans('firefly.no_category'), + // 'sum' => $currency['sum'], + // 'sum_float' => round($currency['sum'], $currency['currency_decimal_places'] ?? 2), + // 'currency_id' => $currency['currency_id'],]; + // } + // + // // sort temp array by amount. + // $amounts = array_column($tempData, 'sum_float'); + // array_multisort($amounts, SORT_DESC, $tempData); + // + // // loop all found currencies and build the data array for the chart. + // /** @var array $currency */ + // foreach ($currencies as $currency) { + // $dataSet = [ + // 'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currency['currency_name']), + // 'type' => 'bar', + // 'currency_symbol' => $currency['currency_symbol'], + // 'entries' => $this->expandNames($tempData), + // ]; + // $chartData[$currency['currency_id']] = $dataSet; + // } + // + // // loop temp data and place data in correct array: + // foreach ($tempData as $entry) { + // $currencyId = $entry['currency_id']; + // $name = $entry['name']; + // $chartData[$currencyId]['entries'][$name] = bcmul($entry['sum'], '-1'); + // } + // + // return $chartData; + // } + + } + + /** + * Small helper function for the revenue and expense account charts. + * TODO double function. + * + * @param array $names + * + * @return array + */ + protected function expandNames(array $names): array + { + $result = []; + foreach ($names as $entry) { + $result[$entry['name']] = 0; + } + + return $result; + } + + /** + * @param array $currency + */ + private function addCurrency(array $currency): void + { + $currencyId = (int) $currency['currency_id']; + + $this->currencies[$currencyId] = $this->currencies[$currencyId] ?? [ + 'currency_id' => $currencyId, + 'currency_name' => $currency['currency_name'], + 'currency_symbol' => $currency['currency_symbol'], + 'currency_code' => $currency['currency_code'], + 'currency_decimal_places' => $currency['currency_decimal_places'], + ]; + } + + /** + * @param Category $category + * @param Collection $accounts + * + * @return array + */ + private function collectExpenses(Category $category, Collection $accounts): array + { + $spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category])); + $tempData = []; + foreach ($spent as $currency) { + $this->addCurrency($currency); + $tempData[] = [ + 'name' => $category->name, + 'sum' => $currency['sum'], + 'sum_float' => round($currency['sum'], $currency['currency_decimal_places']), + 'currency_id' => (int) $currency['currency_id'], + ]; + } + + return $tempData; + } + + /** + * @param Category $category + * @param Collection $accounts + * + * @return array + */ + private function collectIncome(Category $category, Collection $accounts): array + { + $spent = $this->opsRepos->sumIncome($this->start, $this->end, $accounts, new Collection([$category])); + $tempData = []; + foreach ($spent as $currency) { + $this->addCurrency($currency); + $tempData[] = [ + 'name' => $category->name, + 'sum' => $currency['sum'], + 'sum_float' => round($currency['sum'], $currency['currency_decimal_places']), + 'currency_id' => (int) $currency['currency_id'], + ]; + } + + return $tempData; + } + + /** + * @param Collection $accounts + * + * @return array + */ + private function collectNoCatExpenses(Collection $accounts): array + { + $noCatExp = $this->noCatRepos->sumExpenses($this->start, $this->end, $accounts); + $tempData = []; + foreach ($noCatExp as $currency) { + $this->addCurrency($currency); + $tempData[] = [ + 'name' => trans('firefly.no_category'), + 'sum' => $currency['sum'], + 'sum_float' => round($currency['sum'], $currency['currency_decimal_places'] ?? 2), + 'currency_id' => (int) $currency['currency_id'],]; + } + + return $tempData; + } + + /** + * @param Collection $accounts + * + * @return array + */ + private function collectNoCatIncome(Collection $accounts): array + { + $noCatExp = $this->noCatRepos->sumIncome($this->start, $this->end, $accounts); + $tempData = []; + foreach ($noCatExp as $currency) { + $this->addCurrency($currency); + $tempData[] = [ + 'name' => trans('firefly.no_category'), + 'sum' => $currency['sum'], + 'sum_float' => round($currency['sum'], $currency['currency_decimal_places'] ?? 2), + 'currency_id' => (int) $currency['currency_id'],]; + } + + return $tempData; + } + + /** + * @param array $data + * + * @return array + */ + private function createCurrencyGroups(array $data): array + { + $return = []; + $names = $this->expandNames($data); + /** + * @var array $currency + */ + foreach ($this->currencies as $currencyId => $currency) { + $key = sprintf('spent-%d', $currencyId); + $return[$key] = [ + 'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currency['currency_name']), + 'type' => 'bar', + 'currency_symbol' => $currency['currency_symbol'], + 'entries' => $names, + ]; + $key = sprintf('earned-%d', $currencyId); + $return[$key] = [ + 'label' => sprintf('%s (%s)', (string) trans('firefly.earned'), $currency['currency_name']), + 'type' => 'bar', + 'currency_symbol' => $currency['currency_symbol'], + 'data_type' => 'earned', + 'entries' => $names, + ]; + } + + return $return; + } + + /** + * @param array $currencyData + * @param array $monetaryData + * + * @return array + */ + private function insertValues(array $currencyData, array $monetaryData): array + { + /** @var array $array */ + foreach ($monetaryData as $array) { + $direction = $array['sum_float'] < 0 ? 'spent' : 'earned'; + $key = sprintf('%s-%d', $direction, $array['currency_id']); + $category = $array['name']; + $amount = $array['sum_float'] < 0 ? $array['sum_float'] * -1 : $array['sum_float']; + $currencyData[$key]['entries'][$category] = $amount; + + } + + return $currencyData; + } + +} \ No newline at end of file