. */ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Json; use Amount; use Carbon\Carbon; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Support\CacheProperties; use Response; /** * Class BoxController. */ class BoxController extends Controller { /** * @param BudgetRepositoryInterface $repository * * @return \Illuminate\Http\JsonResponse */ public function available(BudgetRepositoryInterface $repository) { $start = session('start', Carbon::now()->startOfMonth()); $end = session('end', Carbon::now()->endOfMonth()); $today = new Carbon; $cache = new CacheProperties; $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty($today); $cache->addProperty('box-available'); if ($cache->has()) { return Response::json($cache->get()); // @codeCoverageIgnore } // get available amount $currency = app('amount')->getDefaultCurrency(); $available = $repository->getAvailableBudget($currency, $start, $end); // get spent amount: $budgets = $repository->getActiveBudgets(); $budgetInformation = $repository->collectBudgetInformation($budgets, $start, $end); $spent = strval(array_sum(array_column($budgetInformation, 'spent'))); $left = bcadd($available, $spent); // left less than zero? then it's zero: if (bccomp($left, '0') === -1) { $left = '0'; } $days = $today->diffInDays($end) + 1; $perDay = '0'; if (0 !== $days) { $perDay = bcdiv($left, strval($days)); } $return = [ 'perDay' => app('amount')->formatAnything($currency, $perDay, false), 'left' => app('amount')->formatAnything($currency, $left, false), ]; $cache->store($return); return Response::json($return); } /** * @param CurrencyRepositoryInterface $repository * * @return \Illuminate\Http\JsonResponse */ public function balance(CurrencyRepositoryInterface $repository) { // Cache result, return cache if present. $start = session('start', Carbon::now()->startOfMonth()); $end = session('end', Carbon::now()->endOfMonth()); $cache = new CacheProperties; $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('box-balance'); if ($cache->has()) { return Response::json($cache->get()); // @codeCoverageIgnore } // prep some arrays: $incomes = []; $expenses = []; $sums = []; // collect income of user: /** @var JournalCollectorInterface $collector */ $collector = app(JournalCollectorInterface::class); $collector->setAllAssetAccounts()->setRange($start, $end) ->setTypes([TransactionType::DEPOSIT]) ->withOpposingAccount(); $set = $collector->getJournals(); /** @var Transaction $transaction */ foreach ($set as $transaction) { $currencyId = intval($transaction->transaction_currency_id); $incomes[$currencyId] = $incomes[$currencyId] ?? '0'; $incomes[$currencyId] = bcadd($incomes[$currencyId], $transaction->transaction_amount); $sums[$currencyId] = $sums[$currencyId] ?? '0'; $sums[$currencyId] = bcadd($sums[$currencyId], $transaction->transaction_amount); } // collect expenses /** @var JournalCollectorInterface $collector */ $collector = app(JournalCollectorInterface::class); $collector->setAllAssetAccounts()->setRange($start, $end) ->setTypes([TransactionType::WITHDRAWAL]) ->withOpposingAccount(); $set = $collector->getJournals(); /** @var Transaction $transaction */ foreach ($set as $transaction) { $currencyId = intval($transaction->transaction_currency_id); $expenses[$currencyId] = $expenses[$currencyId] ?? '0'; $expenses[$currencyId] = bcadd($expenses[$currencyId], $transaction->transaction_amount); $sums[$currencyId] = $sums[$currencyId] ?? '0'; $sums[$currencyId] = bcadd($sums[$currencyId], $transaction->transaction_amount); } // format amounts: foreach ($sums as $currencyId => $amount) { $currency = $repository->findNull($currencyId); $sums[$currencyId] = Amount::formatAnything($currency, $sums[$currencyId], false); $incomes[$currencyId] = Amount::formatAnything($currency, $incomes[$currencyId] ?? '0', false); $expenses[$currencyId] = Amount::formatAnything($currency, $expenses[$currencyId] ?? '0', false); } $response = [ 'incomes' => $incomes, 'expenses' => $expenses, 'sums' => $sums, 'size' => count($sums), ]; $cache->store($response); return Response::json($response); } /** * @param BillRepositoryInterface $repository * * @return \Illuminate\Http\JsonResponse */ public function bills(BillRepositoryInterface $repository) { $start = session('start', Carbon::now()->startOfMonth()); $end = session('end', Carbon::now()->endOfMonth()); $cache = new CacheProperties; $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('box-bills'); if ($cache->has()) { return Response::json($cache->get()); // @codeCoverageIgnore } /* * Since both this method and the chart use the exact same data, we can suffice * with calling the one method in the bill repository that will get this amount. */ $paidAmount = bcmul($repository->getBillsPaidInRange($start, $end), '-1'); $unpaidAmount = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount. $currency = app('amount')->getDefaultCurrency(); $return = [ 'paid' => app('amount')->formatAnything($currency, $paidAmount, false), 'unpaid' => app('amount')->formatAnything($currency, $unpaidAmount, false), ]; $cache->store($return); return Response::json($return); } /** * @param AccountRepositoryInterface $repository * * @return \Illuminate\Http\JsonResponse */ public function netWorth(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepos) { $date = new Carbon(date('Y-m-d')); // needed so its per day. /** @var Carbon $start */ $start = session('start', Carbon::now()->startOfMonth()); /** @var Carbon $end */ $end = session('end', Carbon::now()->endOfMonth()); // start and end in the future? use $end if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) { $date = $end; } // start and end in the past? use $end if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) { $date = $end; } // start in the past, end in the future? use $date $cache = new CacheProperties; $cache->addProperty($date); $cache->addProperty('box-net-worth'); if ($cache->has()) { return Response::json($cache->get()); // @codeCoverageIgnore } $netWorth = []; $accounts = $repository->getActiveAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); $currency = app('amount')->getDefaultCurrency(); $balances = app('steam')->balancesByAccounts($accounts, $date); /** @var Account $account */ foreach ($accounts as $account) { $accountCurrency = $currency; $balance = $balances[$account->id] ?? '0'; $currencyId = intval($account->getMeta('currency_id')); if ($currencyId !== 0) { $accountCurrency = $currencyRepos->findNull($currencyId); } if (!isset($netWorth[$accountCurrency->id])) { $netWorth[$accountCurrency->id]['currency'] = $accountCurrency; $netWorth[$accountCurrency->id]['sum'] = '0'; } $netWorth[$accountCurrency->id]['sum'] = bcadd($netWorth[$accountCurrency->id]['sum'], $balance); } $return = []; foreach ($netWorth as $currencyId => $data) { $return[$currencyId] = app('amount')->formatAnything($data['currency'], $data['sum'], false); } $return = [ 'net_worths' => array_values($return), ]; $cache->store($return); return Response::json($return); } }