diff --git a/app/Helpers/Report/BudgetReportHelper.php b/app/Helpers/Report/BudgetReportHelper.php index d4af9fc8a4..eac93e796c 100644 --- a/app/Helpers/Report/BudgetReportHelper.php +++ b/app/Helpers/Report/BudgetReportHelper.php @@ -52,7 +52,7 @@ class BudgetReportHelper implements BudgetReportHelperInterface public function getBudgetPeriodReport(Carbon $start, Carbon $end, Collection $accounts): array { $budgets = $this->repository->getBudgets(); - $report = $this->repository->getBudgetPeriodReport($budgets, $accounts, $start, $end); + $report = $this->repository->getBudgetPeriodReport($budgets, $accounts, $start, $end, true); $data = $this->filterBudgetPeriodReport($report); return $data; diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index b2da79b704..ab2198be3b 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -209,7 +209,7 @@ class BudgetController extends Controller // the expenses: $periods = Navigation::listOfPeriods($start, $end); - $entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end); + $entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end, false); $budgeted = []; $key = Navigation::preferredCarbonFormat($start, $end); $range = Navigation::preferredRangeFormat($start, $end); diff --git a/app/Http/Controllers/Report/CategoryController.php b/app/Http/Controllers/Report/CategoryController.php index 3e993a9b16..686cdc9760 100644 --- a/app/Http/Controllers/Report/CategoryController.php +++ b/app/Http/Controllers/Report/CategoryController.php @@ -15,11 +15,9 @@ namespace FireflyIII\Http\Controllers\Report; use Carbon\Carbon; -use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Helpers\Report\ReportHelperInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Category; -use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Support\CacheProperties; use Illuminate\Support\Collection; @@ -42,71 +40,15 @@ class CategoryController extends Controller */ public function categoryPeriodReport(Carbon $start, Carbon $end, Collection $accounts) { + /** @var CategoryRepositoryInterface $repository */ $repository = app(CategoryRepositoryInterface::class); $categories = $repository->getCategories(); - $data = []; + $report = $repository->getCategoryPeriodReport($categories, $accounts, $start, $end, true); + $report = $this->filterCategoryPeriodReport($report); + $periods = Navigation::listOfPeriods($start, $end); - // income only: - /** @var JournalCollectorInterface $collector */ - $collector = app(JournalCollectorInterface::class); - $collector->setAccounts($accounts)->setRange($start, $end) - ->withOpposingAccount() - ->enableInternalFilter() - ->setCategories($categories); - - $transactions = $collector->getJournals(); - - // this is the date format we need: - // define period to group on: - $carbonFormat = Navigation::preferredCarbonFormat($start, $end); - - // this is the set of transactions for this period - // in these budgets. Now they must be grouped (manually) - // id, period => amount - $income = []; - foreach ($transactions as $transaction) { - $categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id)); - $date = $transaction->date->format($carbonFormat); - - if (!isset($income[$categoryId])) { - $income[$categoryId]['name'] = $this->getCategoryName($categoryId, $categories); - $income[$categoryId]['sum'] = '0'; - $income[$categoryId]['entries'] = []; - } - - if (!isset($income[$categoryId]['entries'][$date])) { - $income[$categoryId]['entries'][$date] = '0'; - } - $income[$categoryId]['entries'][$date] = bcadd($income[$categoryId]['entries'][$date], $transaction->transaction_amount); - } - - // and now the same for stuff without a category: - /** @var JournalCollectorInterface $collector */ - $collector = app(JournalCollectorInterface::class); - $collector->setAllAssetAccounts()->setRange($start, $end); - $collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]); - $collector->withoutCategory(); - $transactions = $collector->getJournals(); - - $income[0]['entries'] = []; - $income[0]['name'] = strval(trans('firefly.no_category')); - $income[0]['sum'] = '0'; - - foreach ($transactions as $transaction) { - $date = $transaction->date->format($carbonFormat); - - if (!isset($income[0]['entries'][$date])) { - $income[0]['entries'][$date] = '0'; - } - $income[0]['entries'][$date] = bcadd($income[0]['entries'][$date], $transaction->transaction_amount); - } - - $periods = Navigation::listOfPeriods($start, $end); - - $income = $this->filterCategoryPeriodReport($income); - - $result = view('reports.partials.category-period', compact('categories', 'periods', 'income'))->render(); + $result = view('reports.partials.category-period', compact('categories', 'periods', 'report'))->render(); return $result; } @@ -148,18 +90,20 @@ class CategoryController extends Controller */ private function filterCategoryPeriodReport(array $data): array { - /** - * @var int $categoryId - * @var array $set - */ - foreach ($data as $categoryId => $set) { - $sum = '0'; - foreach ($set['entries'] as $amount) { - $sum = bcadd($amount, $sum); - } - $data[$categoryId]['sum'] = $sum; - if (bccomp('0', $sum) === 0) { - unset($data[$categoryId]); + foreach ($data as $key => $set) { + /** + * @var int $categoryId + * @var array $set + */ + foreach ($set as $categoryId => $info) { + $sum = '0'; + foreach ($info['entries'] as $amount) { + $sum = bcadd($amount, $sum); + } + $data[$key][$categoryId]['sum'] = $sum; + if (bccomp('0', $sum) === 0) { + unset($data[$key][$categoryId]); + } } } diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index d76c229ac3..47cf4e7273 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -212,19 +212,18 @@ class BudgetRepository implements BudgetRepositoryInterface } /** - * This method is being used to generate the budget overview in the year/multi-year report. More specifically, this - * method runs the query and returns the result that is used for this report. - * - * The query is used in both the year/multi-year budget overview AND in the accompanying chart. + * This method is being used to generate the budget overview in the year/multi-year report. Its used + * in both the year/multi-year budget overview AND in the accompanying chart. * * @param Collection $budgets * @param Collection $accounts * @param Carbon $start * @param Carbon $end + * @param bool $noBudget * * @return array */ - public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array + public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end, bool $noBudget): array { $carbonFormat = Navigation::preferredCarbonFormat($start, $end); $data = []; @@ -252,8 +251,11 @@ class BudgetRepository implements BudgetRepositoryInterface $date = $transaction->date->format($carbonFormat); $data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date] ?? '0', $transaction->transaction_amount); } - // and now the same for stuff without a budget: - $data[0] = $this->getNoBudgetPeriodReport($start, $end); + + if ($noBudget) { + // and now the same for stuff without a budget: + $data[0] = $this->getNoBudgetPeriodReport($start, $end); + } return $data; diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index f81788a435..296b06ed4f 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -96,10 +96,11 @@ interface BudgetRepositoryInterface * @param Collection $accounts * @param Carbon $start * @param Carbon $end + * @param bool $noBudget * * @return array */ - public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array; + public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end, bool $noBudget): array; /** * @return Collection @@ -119,7 +120,7 @@ interface BudgetRepositoryInterface * * @return string */ - public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) : string; + public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): string; /** * @param Collection $accounts @@ -143,7 +144,7 @@ interface BudgetRepositoryInterface * * @return Budget */ - public function update(Budget $budget, array $data) : Budget; + public function update(Budget $budget, array $data): Budget; /** * @param Budget $budget @@ -154,6 +155,6 @@ interface BudgetRepositoryInterface * * @return BudgetLimit */ - public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount) : BudgetLimit; + public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount): BudgetLimit; } diff --git a/app/Repositories/Category/CategoryRepository.php b/app/Repositories/Category/CategoryRepository.php index 98d613e9ba..403df60c5e 100644 --- a/app/Repositories/Category/CategoryRepository.php +++ b/app/Repositories/Category/CategoryRepository.php @@ -15,12 +15,15 @@ namespace FireflyIII\Repositories\Category; use Carbon\Carbon; use DB; +use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Models\Category; +use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\User; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Collection; +use Navigation; /** * Class CategoryRepository @@ -172,6 +175,32 @@ class CategoryRepository implements CategoryRepositoryInterface return $set; } + /** + * This method is being used to generate the category overview in the year/multi-year report. Its used + * in both the year/multi-year budget overview AND in the accompanying chart. + * + * @param Collection $categories + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * @param @bool $noCategory + * + * @return array + */ + public function getCategoryPeriodReport(Collection $categories, Collection $accounts, Carbon $start, Carbon $end, bool $noCategory): array + { + $data = [ + 'income' => $this->getCategoryReportData($categories, $accounts, $start, $end, $noCategory, [TransactionType::DEPOSIT, TransactionType::TRANSFER]), + 'expense' => $this->getCategoryReportData( + $categories, $accounts, $start, $end, $noCategory, [TransactionType::WITHDRAWAL, TransactionType::TRANSFER] + ), + ]; + + return $data; + + + } + /** * @param Category $category * @param Collection $accounts @@ -233,6 +262,7 @@ class CategoryRepository implements CategoryRepositoryInterface { $sum = $this->sumInPeriod($categories, $accounts, TransactionType::WITHDRAWAL, $start, $end); $sum = bcmul($sum, '-1'); + return $sum; } @@ -284,6 +314,55 @@ class CategoryRepository implements CategoryRepositoryInterface return $category; } + /** + * @param Collection $categories + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * @param bool $noCategory + * @param array $types + * + * @return array + */ + private function getCategoryReportData(Collection $categories, Collection $accounts, Carbon $start, Carbon $end, bool $noCategory, array $types): array + { + $carbonFormat = Navigation::preferredCarbonFormat($start, $end); + $data = []; + // prep data array: + /** @var Category $category */ + foreach ($categories as $category) { + $data[$category->id] = [ + 'name' => $category->name, + 'sum' => '0', + 'entries' => [], + ]; + } + + // get all transactions: + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setAccounts($accounts)->setRange($start, $end); + $collector->setCategories($categories)->setTypes($types) + ->withOpposingAccount() + ->enableInternalFilter(); + $transactions = $collector->getJournals(); + + // loop transactions: + /** @var Transaction $transaction */ + foreach ($transactions as $transaction) { + $categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id)); + $date = $transaction->date->format($carbonFormat); + $data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', $transaction->transaction_amount); + } + + if ($noCategory) { + // and now the same for stuff without a budget: + //$data[0] = $this->getNoBudgetPeriodReport($start, $end); + } + + return $data; + } + /** * @param Collection $categories * @param Collection $accounts @@ -404,5 +483,4 @@ class CategoryRepository implements CategoryRepositoryInterface return $sum; } - } diff --git a/app/Repositories/Category/CategoryRepositoryInterface.php b/app/Repositories/Category/CategoryRepositoryInterface.php index d088eebe5d..feb479c52d 100644 --- a/app/Repositories/Category/CategoryRepositoryInterface.php +++ b/app/Repositories/Category/CategoryRepositoryInterface.php @@ -49,7 +49,7 @@ interface CategoryRepositoryInterface * * @return string */ - public function earnedInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end) :string; + public function earnedInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end): string; /** * Find a category @@ -58,7 +58,7 @@ interface CategoryRepositoryInterface * * @return Category */ - public function find(int $categoryId) : Category; + public function find(int $categoryId): Category; /** * Find a category @@ -67,7 +67,7 @@ interface CategoryRepositoryInterface * * @return Category */ - public function findByName(string $name) : Category; + public function findByName(string $name): Category; /** * @param Category $category @@ -83,6 +83,20 @@ interface CategoryRepositoryInterface */ public function getCategories(): Collection; + /** + * This method is being used to generate the category overview in the year/multi-year report. Its used + * in both the year/multi-year budget overview AND in the accompanying chart. + * + * @param Collection $categories + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * @param bool $noCategory + * + * @return array + */ + public function getCategoryPeriodReport(Collection $categories, Collection $accounts, Carbon $start, Carbon $end, bool $noCategory): array; + /** * Return most recent transaction(journal) date. * @@ -110,7 +124,7 @@ interface CategoryRepositoryInterface * * @return string */ - public function spentInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end) : string; + public function spentInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end): string; /** * @param array $data diff --git a/resources/views/reports/partials/category-period.twig b/resources/views/reports/partials/category-period.twig index a7fbebadd6..7a20b962f5 100644 --- a/resources/views/reports/partials/category-period.twig +++ b/resources/views/reports/partials/category-period.twig @@ -18,7 +18,7 @@
{% for category in categories %} - {% if income[category.id] %} + {% if report.income[category.id] or report.expense[category.id] %}