generator = app(ReportChartGeneratorInterface::class); } /** * This chart, by default, is shown on the multi-year and year report pages, * which means that giving it a 2 week "period" should be enough granularity. * * @param Collection $accounts * @param Carbon $start * @param Carbon $end * @return \Illuminate\Http\JsonResponse */ public function netWorth(Collection $accounts, Carbon $start, Carbon $end) { // chart properties for cache: $cache = new CacheProperties; $cache->addProperty('netWorth'); $cache->addProperty($start); $cache->addProperty($accounts); $cache->addProperty($end); if ($cache->has()) { return Response::json($cache->get()); } $ids = $accounts->pluck('id')->toArray(); $current = clone $start; $entries = new Collection; while ($current < $end) { $balances = Steam::balancesById($ids, $current); $sum = $this->arraySum($balances); $entries->push( [ 'date' => clone $current, 'net-worth' => $sum, ] ); $current->addDays(7); } $data = $this->generator->netWorth($entries); $cache->store($data); return Response::json($data); } /** * Shows income and expense, debet/credit: operations * * @param Collection $accounts * @param Carbon $start * @param Carbon $end * * * @return \Illuminate\Http\JsonResponse */ public function operations(Collection $accounts, Carbon $start, Carbon $end) { // chart properties for cache: $cache = new CacheProperties; $cache->addProperty('yearInOut'); $cache->addProperty($start); $cache->addProperty($accounts); $cache->addProperty($end); if ($cache->has()) { return Response::json($cache->get()); } $chartSource = $this->getYearData($accounts, $start, $end); if ($start->diffInMonths($end) > 12) { // data = method X $data = $this->multiYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end); $cache->store($data); return Response::json($data); } // data = method Y $data = $this->singleYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end); $cache->store($data); return Response::json($data); } /** * Shows sum income and expense, debet/credit: operations * @param Carbon $start * @param Carbon $end * @param Collection $accounts * * @return \Illuminate\Http\JsonResponse */ public function sum(Collection $accounts, Carbon $start, Carbon $end) { // chart properties for cache: $cache = new CacheProperties; $cache->addProperty('yearInOutSummarized'); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty($accounts); if ($cache->has()) { return Response::json($cache->get()); } $chartSource = $this->getYearData($accounts, $start, $end); if ($start->diffInMonths($end) > 12) { // per year $data = $this->multiYearSum($chartSource['earned'], $chartSource['spent'], $start, $end); $cache->store($data); return Response::json($data); } // per month! $data = $this->singleYearSum($chartSource['earned'], $chartSource['spent'], $start, $end); $cache->store($data); return Response::json($data); } /** * @param array $earned * @param array $spent * @param Carbon $start * @param Carbon $end * * @return array */ protected function multiYearOperations(array $earned, array $spent, Carbon $start, Carbon $end) { $entries = new Collection; while ($start < $end) { $incomeSum = $this->pluckFromArray($start->year, $earned); $expenseSum = $this->pluckFromArray($start->year, $spent); $entries->push([clone $start, $incomeSum, $expenseSum]); $start->addYear(); } $data = $this->generator->multiYearOperations($entries); return $data; } /** * @param array $earned * @param array $spent * @param Carbon $start * @param Carbon $end * * @return array */ protected function multiYearSum(array $earned, array $spent, Carbon $start, Carbon $end) { $income = '0'; $expense = '0'; $count = 0; while ($start < $end) { $currentIncome = $this->pluckFromArray($start->year, $earned); $currentExpense = $this->pluckFromArray($start->year, $spent); $income = bcadd($income, $currentIncome); $expense = bcadd($expense, $currentExpense); $count++; $start->addYear(); } $data = $this->generator->multiYearSum($income, $expense, $count); return $data; } /** * @param int $year * @param array $set * * @return string */ protected function pluckFromArray($year, array $set) { $sum = '0'; foreach ($set as $date => $amount) { if (substr($date, 0, 4) == $year) { $sum = bcadd($sum, $amount); } } return $sum; } /** * @param array $earned * @param array $spent * @param Carbon $start * @param Carbon $end * * @return array */ protected function singleYearOperations(array $earned, array $spent, Carbon $start, Carbon $end) { // per month? simply use each month. $entries = new Collection; while ($start < $end) { // total income and total expenses: $date = $start->format('Y-m'); $incomeSum = isset($earned[$date]) ? $earned[$date] : 0; $expenseSum = isset($spent[$date]) ? $spent[$date] : 0; $entries->push([clone $start, $incomeSum, $expenseSum]); $start->addMonth(); } $data = $this->generator->yearOperations($entries); return $data; } /** * @param array $earned * @param array $spent * @param Carbon $start * @param Carbon $end * * @return array */ protected function singleYearSum(array $earned, array $spent, Carbon $start, Carbon $end) { $income = '0'; $expense = '0'; $count = 0; while ($start < $end) { $date = $start->format('Y-m'); $currentIncome = isset($earned[$date]) ? $earned[$date] : 0; $currentExpense = isset($spent[$date]) ? $spent[$date] : 0; $income = bcadd($income, $currentIncome); $expense = bcadd($expense, $currentExpense); $count++; $start->addMonth(); } $data = $this->generator->yearSum($income, $expense, $count); return $data; } /** * @param $array * * @return string */ private function arraySum($array) : string { $sum = '0'; foreach ($array as $entry) { $sum = bcadd($sum, $entry); } return $sum; } /** * @param Collection $accounts * @param Carbon $start * @param Carbon $end * * @return array */ private function getYearData(Collection $accounts, Carbon $start, Carbon $end): array { $tasker = app(AccountTaskerInterface::class); $currentStart = clone $start; $spentArray = []; $earnedArray = []; while ($currentStart <= $end) { $currentEnd = Navigation::endOfPeriod($currentStart, '1M'); $date = $currentStart->format('Y-m'); $spent = $tasker->amountOutInPeriod($accounts, $accounts, $currentStart, $currentEnd); $earned = $tasker->amountInInPeriod($accounts, $accounts, $currentStart, $currentEnd); $spentArray[$date] = bcmul($spent, '-1'); $earnedArray[$date] = $earned; $currentStart = Navigation::addPeriod($currentStart, '1M', 0); } return [ 'spent' => $spentArray, 'earned' => $earnedArray, ]; } }