mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 02:36:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			183 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| declare(strict_types = 1);
 | |
| /**
 | |
|  * BudgetReportHelper.php
 | |
|  * Copyright (C) 2016 thegrumpydictator@gmail.com
 | |
|  *
 | |
|  * This software may be modified and distributed under the terms
 | |
|  * of the MIT license.  See the LICENSE file for details.
 | |
|  */
 | |
| 
 | |
| namespace FireflyIII\Helpers\Report;
 | |
| 
 | |
| 
 | |
| use Carbon\Carbon;
 | |
| use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
 | |
| use FireflyIII\Helpers\Collection\BudgetLine;
 | |
| use FireflyIII\Models\Budget;
 | |
| use FireflyIII\Models\LimitRepetition;
 | |
| use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
 | |
| use Illuminate\Support\Collection;
 | |
| 
 | |
| /**
 | |
|  * Class BudgetReportHelper
 | |
|  *
 | |
|  * @package FireflyIII\Helpers\Report
 | |
|  */
 | |
| class BudgetReportHelper implements BudgetReportHelperInterface
 | |
| {
 | |
|     /** @var BudgetRepositoryInterface */
 | |
|     private $repository;
 | |
| 
 | |
|     /**
 | |
|      * BudgetReportHelper constructor.
 | |
|      *
 | |
|      * @param BudgetRepositoryInterface $repository
 | |
|      */
 | |
|     public function __construct(BudgetRepositoryInterface $repository)
 | |
|     {
 | |
|         $this->repository = $repository;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param Carbon     $start
 | |
|      * @param Carbon     $end
 | |
|      * @param Collection $accounts
 | |
|      *
 | |
|      * @return BudgetCollection
 | |
|      */
 | |
|     public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): BudgetCollection
 | |
|     {
 | |
|         $object = new BudgetCollection;
 | |
|         $set    = $this->repository->getBudgets();
 | |
| 
 | |
|         /** @var Budget $budget */
 | |
|         foreach ($set as $budget) {
 | |
|             $repetitions = $budget->limitrepetitions()->before($end)->after($start)->get();
 | |
| 
 | |
|             // no repetition(s) for this budget:
 | |
|             if ($repetitions->count() == 0) {
 | |
|                 // spent for budget in time range:
 | |
|                 $spent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
 | |
| 
 | |
|                 if ($spent > 0) {
 | |
|                     $budgetLine = new BudgetLine;
 | |
|                     $budgetLine->setBudget($budget);
 | |
|                     $budgetLine->setOverspent($spent);
 | |
|                     $object->addOverspent($spent);
 | |
|                     $object->addBudgetLine($budgetLine);
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
|             // one or more repetitions for budget:
 | |
|             /** @var LimitRepetition $repetition */
 | |
|             foreach ($repetitions as $repetition) {
 | |
|                 $data = $this->calculateExpenses($budget, $repetition, $accounts);
 | |
| 
 | |
|                 $budgetLine = new BudgetLine;
 | |
|                 $budgetLine->setBudget($budget);
 | |
|                 $budgetLine->setRepetition($repetition);
 | |
|                 $budgetLine->setLeft($data['left']);
 | |
|                 $budgetLine->setSpent($data['expenses']);
 | |
|                 $budgetLine->setOverspent($data['overspent']);
 | |
|                 $budgetLine->setBudgeted($repetition->amount);
 | |
| 
 | |
|                 $object->addBudgeted($repetition->amount);
 | |
|                 $object->addSpent($data['spent']);
 | |
|                 $object->addLeft($data['left']);
 | |
|                 $object->addOverspent($data['overspent']);
 | |
|                 $object->addBudgetLine($budgetLine);
 | |
| 
 | |
|             }
 | |
| 
 | |
|         }
 | |
| 
 | |
|         // stuff outside of budgets:
 | |
| 
 | |
|         $noBudget = $this->repository->spentInPeriodWithoutBudget($accounts, $start, $end);
 | |
|         $budgetLine = new BudgetLine;
 | |
|         $budgetLine->setOverspent($noBudget);
 | |
|         $budgetLine->setSpent($noBudget);
 | |
|         $object->addOverspent($noBudget);
 | |
|         $object->addBudgetLine($budgetLine);
 | |
| 
 | |
|         return $object;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param Carbon     $start
 | |
|      * @param Carbon     $end
 | |
|      * @param Collection $accounts
 | |
|      *
 | |
|      * @return Collection
 | |
|      */
 | |
|     public function getBudgetsWithExpenses(Carbon $start, Carbon $end, Collection $accounts): Collection
 | |
|     {
 | |
|         /** @var BudgetRepositoryInterface $repository */
 | |
|         $repository = app(BudgetRepositoryInterface::class);
 | |
|         $budgets    = $repository->getActiveBudgets();
 | |
| 
 | |
|         $set = new Collection;
 | |
|         /** @var Budget $budget */
 | |
|         foreach ($budgets as $budget) {
 | |
|             $total = $repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
 | |
|             if (bccomp($total, '0') === -1) {
 | |
|                 $set->push($budget);
 | |
|             }
 | |
|         }
 | |
|         $set = $set->sortBy(
 | |
|             function (Budget $budget) {
 | |
|                 return $budget->name;
 | |
|             }
 | |
|         );
 | |
| 
 | |
|         return $set;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Take the array as returned by CategoryRepositoryInterface::spentPerDay and CategoryRepositoryInterface::earnedByDay
 | |
|      * and sum up everything in the array in the given range.
 | |
|      *
 | |
|      * @param Carbon $start
 | |
|      * @param Carbon $end
 | |
|      * @param array  $array
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     protected function getSumOfRange(Carbon $start, Carbon $end, array $array)
 | |
|     {
 | |
|         $sum          = '0';
 | |
|         $currentStart = clone $start; // to not mess with the original one
 | |
|         $currentEnd   = clone $end; // to not mess with the original one
 | |
| 
 | |
|         while ($currentStart <= $currentEnd) {
 | |
|             $date = $currentStart->format('Y-m-d');
 | |
|             if (isset($array[$date])) {
 | |
|                 $sum = bcadd($sum, $array[$date]);
 | |
|             }
 | |
|             $currentStart->addDay();
 | |
|         }
 | |
| 
 | |
|         return $sum;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param Budget          $budget
 | |
|      * @param LimitRepetition $repetition
 | |
|      * @param Collection      $accounts
 | |
|      *
 | |
|      * @return array
 | |
|      */
 | |
|     private function calculateExpenses(Budget $budget, LimitRepetition $repetition, Collection $accounts): array
 | |
|     {
 | |
|         $array              = [];
 | |
|         $expenses           = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $repetition->startdate, $repetition->enddate);
 | |
|         $array['left']      = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? bcadd($repetition->amount, $expenses) : '0';
 | |
|         $array['spent']     = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? $expenses : '0';
 | |
|         $array['overspent'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? '0' : bcadd($expenses, $repetition->amount);
 | |
| 
 | |
|         return $array;
 | |
| 
 | |
|     }
 | |
| }
 |