mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 10:47:00 +00:00 
			
		
		
		
	Building report from issue #386
This commit is contained in:
		| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
|     </thead> | ||||
|     <tbody> | ||||
|     {% for category in categories %} | ||||
|         {% if income[category.id] %} | ||||
|         {% if report.income[category.id] or report.expense[category.id] %} | ||||
|         <tr> | ||||
|             <td data-value="{{ category.name }}"> | ||||
|                 <a title="{{ category.name }}" href="#" data-category="{{ category.id }}" class="category-chart-activate">{{ category.name }}</a> | ||||
| @@ -26,26 +26,30 @@ | ||||
|  | ||||
|             {% for key, period in periods %} | ||||
|                 {# income first #} | ||||
|                 {% if(income[category.id].entries[key]) %} | ||||
|                     <td data-value="{{ income[category.id].entries[key] }}"> | ||||
|                         {{ income[category.id].entries[key]|formatAmount }} | ||||
|                 {% if(report.income[category.id].entries[key]) %} | ||||
|                     <td data-value="{{ report.income[category.id].entries[key] }}"> | ||||
|                         {{ report.income[category.id].entries[key]|formatAmount }} | ||||
|                     </td> | ||||
|                 {% else %} | ||||
|                     <td data-value="0"> | ||||
|                         {{ 0|formatAmount }} | ||||
|                     </td> | ||||
|                 {% endif %} | ||||
|  | ||||
|                 {# expenses #} | ||||
|                 <td data-value="0"> | ||||
|                     <!-- expense --> | ||||
|                 </td> | ||||
|                 {% if(report.expense[category.id].entries[key]) %} | ||||
|                     <td data-value="{{ report.expense[category.id].entries[key] }}"> | ||||
|                         {{ report.expense[category.id].entries[key]|formatAmount }} | ||||
|                     </td> | ||||
|                 {% else %} | ||||
|                     <td data-value="0"> | ||||
|                     </td> | ||||
|                 {% endif %} | ||||
|             {% endfor %} | ||||
|             <td data-value="{{ info.sum }}"> | ||||
|                 0 | ||||
|             <td data-value="{{ report.income[category.id].sum }}"> | ||||
|                 {{ report.income[category.id].sum }} | ||||
|             </td> | ||||
|             <td data-value="{{ info.sum }}"> | ||||
|                 1 | ||||
|             <td data-value="{{ report.expense[category.id].sum }}"> | ||||
|                 {{ report.expense[category.id].sum }} | ||||
|             </td> | ||||
|         </tr> | ||||
|     {% endif %} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user