Files
firefly-iii/app/Support/Form/AccountForm.php
Aniruddha Maru 9d409a7412 Fix recurring transactions create
- If there's a lot of accounts to calculate balances for, then recurring transactions create page
  doesn't load. Partly because it has to calculate a lot of balances, but partly because the cache
  isn't being used at all because date is `new Date` rather than say, end of month.

Fix: Change Steam balance calculator to always default cache using end of month. Since cache is
'invalidated' upon any edit, there's no reason to use current datetime anywhere its not explicitly
required by user flow.
Fix: Don't calculate balances for revenue / expense accounts since those are unbounded.

Issue: #3597
2020-07-25 16:16:29 -07:00

233 lines
8.2 KiB
PHP

<?php
/**
* AccountForm.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Form;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
use Throwable;
/**
* Class AccountForm
*
* All form methods that are account related.
*
* TODO describe all methods.
* TODO optimize repositories and methods.
*/
class AccountForm
{
use FormSupport;
private function getAccountsGrouped(array $types, AccountRepositoryInterface $repository = null): array
{
if (null === $repository) {
$repository = $this->getAccountRepository();
}
$accountList = $repository->getActiveAccountsByType($types);
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
$balanceTypes = [AccountType::ASSET, AccountType::DEFAULT, AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
$defaultCurrency = app('amount')->getDefaultCurrency();
$grouped = [];
/** @var Account $account */
foreach ($accountList as $account) {
$accountWithBalance = $account->name;
if (in_array($account->accountType->type, $balanceTypes, true)) {
$balance = app('steam')->balance($account);
$currency = $repository->getAccountCurrency($account) ?? $defaultCurrency;
$formatted = app('amount')->formatAnything($currency, $balance, false);
$accountWithBalance = sprintf('%s (%s)', $account->name, $formatted);
}
$role = (string)$repository->getMetaValue($account, 'account_role');
if (in_array($account->accountType->type, $liabilityTypes, true)) {
$role = sprintf('l_%s', $account->accountType->type);
} elseif ('' === $role) {
if (AccountType::EXPENSE === $account->accountType->type) {
$role = 'expense_account';
} elseif (AccountType::REVENUE === $account->accountType->type) {
$role = 'revenue_account';
} else {
$role = 'no_account_type';
}
}
$key = (string)trans(sprintf('firefly.opt_group_%s', $role));
$grouped[$key][$account->id] = $accountWithBalance;
}
return $grouped;
}
/**
* Shows a <select> with all active asset accounts.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function activeAssetAccountList(string $name, $value = null, array $options = null): string
{
$types = [AccountType::ASSET, AccountType::DEFAULT];
$grouped = $this->getAccountsGrouped($types);
return $this->select($name, $grouped, $value, $options);
}
/**
* Return a list that includes liabilities.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function activeLongAccountList(string $name, $value = null, array $options = null): string
{
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
$grouped = $this->getAccountsGrouped($types);
return $this->select($name, $grouped, $value, $options);
}
/**
* Grouped dropdown list of all accounts that are valid as the destination of a withdrawal.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function activeWithdrawalDestinations(string $name, $value = null, array $options = null): string
{
$types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::EXPENSE,];
$repository = $this->getAccountRepository();
$grouped = $this->getAccountsGrouped($types, $repository);
$cash = $repository->getCashAccount();
$key = (string)trans('firefly.cash_account_type');
$grouped[$key][$cash->id] = sprintf('(%s)', (string)trans('firefly.cash'));
return $this->select($name, $grouped, $value, $options);
}
/**
* Grouped dropdown list of all accounts that are valid as the destination of a withdrawal.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function activeDepositDestinations(string $name, $value = null, array $options = null): string
{
$types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::REVENUE,];
$repository = $this->getAccountRepository();
$grouped = $this->getAccountsGrouped($types, $repository);
$cash = $repository->getCashAccount();
$key = (string)trans('firefly.cash_account_type');
$grouped[$key][$cash->id] = sprintf('(%s)', (string)trans('firefly.cash'));
return $this->select($name, $grouped, $value, $options);
}
/**
* Check list of asset accounts.
*
* @param string $name
* @param array $options
*
* @return string
*
*/
public function assetAccountCheckList(string $name, array $options = null): string
{
$options = $options ?? [];
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$selected = request()->old($name) ?? [];
// get all asset accounts:
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT];
$grouped = $this->getAccountsGrouped($types);
unset($options['class']);
try {
$html = view('form.assetAccountCheckList', compact('classes', 'selected', 'name', 'label', 'options', 'grouped'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render assetAccountCheckList(): %s', $e->getMessage()));
$html = 'Could not render assetAccountCheckList.';
}
return $html;
}
/**
* Basic list of asset accounts.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function assetAccountList(string $name, $value = null, array $options = null): string
{
$types = [AccountType::ASSET, AccountType::DEFAULT];
$grouped = $this->getAccountsGrouped($types);
return $this->select($name, $grouped, $value, $options);
}
/**
* Same list but all liabilities as well.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function longAccountList(string $name, $value = null, array $options = null): string
{
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
$grouped = $this->getAccountsGrouped($types);
return $this->select($name, $grouped, $value, $options);
}
}