Auto commit for release 'branch-v6.2' on 2024-12-22

This commit is contained in:
github-actions
2024-12-22 20:37:54 +01:00
parent d90ac519f7
commit c0499df4ec
91 changed files with 1153 additions and 1163 deletions

View File

@@ -56,8 +56,8 @@ class AccountController extends Controller
function ($request, $next) { function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class); $this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request)); $this->repository->setUserGroup($this->validateUserGroup($request));
$this->chartData = new ChartData(); $this->chartData = new ChartData();
$this->default = app('amount')->getDefaultCurrency(); $this->default = app('amount')->getDefaultCurrency();
return $next($request); return $next($request);
} }
@@ -92,11 +92,11 @@ class AccountController extends Controller
*/ */
private function renderAccountData(array $params, Account $account): void private function renderAccountData(array $params, Account $account): void
{ {
$currency = $this->repository->getAccountCurrency($account); $currency = $this->repository->getAccountCurrency($account);
if (null === $currency) { if (null === $currency) {
$currency = $this->default; $currency = $this->default;
} }
$currentSet = [ $currentSet = [
'label' => $account->name, 'label' => $account->name,
// the currency that belongs to the account. // the currency that belongs to the account.
@@ -117,18 +117,18 @@ class AccountController extends Controller
'entries' => [], 'entries' => [],
'native_entries' => [], 'native_entries' => [],
]; ];
$currentStart = clone $params['start']; $currentStart = clone $params['start'];
$range = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $currency); $range = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $currency);
$previous = array_values($range)[0]['balance']; $previous = array_values($range)[0]['balance'];
$previousNative = array_values($range)[0]['native_balance']; $previousNative = array_values($range)[0]['native_balance'];
while ($currentStart <= $params['end']) { while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous; $balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$balanceNative = array_key_exists($format, $range) ? $range[$format]['balance_native'] : $previousNative; $balanceNative = array_key_exists($format, $range) ? $range[$format]['balance_native'] : $previousNative;
$previous = $balance; $previous = $balance;
$previousNative = $balanceNative; $previousNative = $balanceNative;
$currentStart->addDay(); $currentStart->addDay();
$currentSet['entries'][$label] = $balance; $currentSet['entries'][$label] = $balance;

View File

@@ -29,11 +29,9 @@ use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Middleware\Installer; use FireflyIII\Http\Middleware\Installer;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;

View File

@@ -103,7 +103,7 @@ class PreferencesController extends Controller
$darkMode = app('preferences')->get('darkMode', 'browser')->data; $darkMode = app('preferences')->get('darkMode', 'browser')->data;
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data; $customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
$fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data; $fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
$convertToNative =app('preferences')->get('convert_to_native', false)->data; $convertToNative = app('preferences')->get('convert_to_native', false)->data;
if (is_array($fiscalYearStartStr)) { if (is_array($fiscalYearStartStr)) {
$fiscalYearStartStr = '01-01'; $fiscalYearStartStr = '01-01';
} }
@@ -257,7 +257,7 @@ class PreferencesController extends Controller
} }
// convert native // convert native
$convertToNative = 1 === (int) $request->get('convertToNative'); $convertToNative = 1 === (int) $request->get('convertToNative');
app('preferences')->set('convert_to_native', $convertToNative); app('preferences')->set('convert_to_native', $convertToNative);
// custom fiscal year // custom fiscal year

View File

@@ -28,7 +28,6 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use NumberFormatter;
/** /**
* Class Amount. * Class Amount.
@@ -56,15 +55,15 @@ class Amount
*/ */
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{ {
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
$rounded = app('steam')->bcround($amount, $decimalPlaces); $rounded = app('steam')->bcround($amount, $decimalPlaces);
$coloured ??= true; $coloured ??= true;
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY); $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol); $fmt->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(\NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
$result = (string) $fmt->format((float) $rounded); // intentional float $result = (string) $fmt->format((float) $rounded); // intentional float
if (true === $coloured) { if (true === $coloured) {
if (1 === bccomp($rounded, '0')) { if (1 === bccomp($rounded, '0')) {
@@ -110,7 +109,7 @@ class Amount
public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty('getDefaultCurrencyByGroup'); $cache->addProperty('getDefaultCurrencyByGroup');
$cache->addProperty($userGroup->id); $cache->addProperty($userGroup->id);
if ($cache->has()) { if ($cache->has()) {
@@ -173,23 +172,23 @@ class Amount
private function getLocaleInfo(): array private function getLocaleInfo(): array
{ {
// get config from preference, not from translation: // get config from preference, not from translation:
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale); $array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array); setlocale(LC_MONETARY, $array);
$info = localeconv(); $info = localeconv();
// correct variables // correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes'); $info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes'); $info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space'); $info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
$info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space'); $info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY); $fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL); $info['mon_decimal_point'] = $fmt->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL); $info['mon_thousands_sep'] = $fmt->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
return $info; return $info;
} }
@@ -209,7 +208,7 @@ class Amount
public static function getAmountJsConfig(bool $sepBySpace, int $signPosn, string $sign, bool $csPrecedes): string public static function getAmountJsConfig(bool $sepBySpace, int $signPosn, string $sign, bool $csPrecedes): string
{ {
// negative first: // negative first:
$space = ' '; $space = ' ';
// require space between symbol and amount? // require space between symbol and amount?
if (false === $sepBySpace) { if (false === $sepBySpace) {
@@ -218,11 +217,11 @@ class Amount
// there are five possible positions for the "+" or "-" sign (if it is even used) // there are five possible positions for the "+" or "-" sign (if it is even used)
// pos_a and pos_e could be the ( and ) symbol. // pos_a and pos_e could be the ( and ) symbol.
$posA = ''; // before everything $posA = ''; // before everything
$posB = ''; // before currency symbol $posB = ''; // before currency symbol
$posC = ''; // after currency symbol $posC = ''; // after currency symbol
$posD = ''; // before amount $posD = ''; // before amount
$posE = ''; // after everything $posE = ''; // after everything
// format would be (currency before amount) // format would be (currency before amount)
// AB%sC_D%vE // AB%sC_D%vE
@@ -264,11 +263,11 @@ class Amount
} }
// default is amount before currency // default is amount before currency
$format = $posA . $posD . '%v' . $space . $posB . '%s' . $posC . $posE; $format = $posA.$posD.'%v'.$space.$posB.'%s'.$posC.$posE;
if ($csPrecedes) { if ($csPrecedes) {
// alternative is currency before amount // alternative is currency before amount
$format = $posA . $posB . '%s' . $posC . $space . $posD . '%v' . $posE; $format = $posA.$posB.'%s'.$posC.$space.$posD.'%v'.$posE;
} }
return $format; return $format;

View File

@@ -47,7 +47,7 @@ class RemoteUserGuard implements Guard
public function __construct(UserProvider $provider, Application $app) public function __construct(UserProvider $provider, Application $app)
{ {
/** @var null|Request $request */ /** @var null|Request $request */
$request = $app->get('request'); $request = $app->get('request');
app('log')->debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri())); app('log')->debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
$this->application = $app; $this->application = $app;
$this->provider = $provider; $this->provider = $provider;
@@ -63,8 +63,8 @@ class RemoteUserGuard implements Guard
return; return;
} }
// Get the user identifier from $_SERVER or apache filtered headers // Get the user identifier from $_SERVER or apache filtered headers
$header = config('auth.guard_header', 'REMOTE_USER'); $header = config('auth.guard_header', 'REMOTE_USER');
$userID = request()->server($header) ?? null; $userID = request()->server($header) ?? null;
if (function_exists('apache_request_headers')) { if (function_exists('apache_request_headers')) {
app('log')->debug('Use apache_request_headers to find user ID.'); app('log')->debug('Use apache_request_headers to find user ID.');
@@ -83,7 +83,7 @@ class RemoteUserGuard implements Guard
$retrievedUser = $this->provider->retrieveById($userID); $retrievedUser = $this->provider->retrieveById($userID);
// store email address if present in header and not already set. // store email address if present in header and not already set.
$header = config('auth.guard_email'); $header = config('auth.guard_email');
if (null !== $header) { if (null !== $header) {
$emailAddress = (string) (request()->server($header) ?? apache_request_headers()[$header] ?? null); $emailAddress = (string) (request()->server($header) ?? apache_request_headers()[$header] ?? null);
@@ -99,7 +99,7 @@ class RemoteUserGuard implements Guard
} }
app('log')->debug(sprintf('Result of getting user from provider: %s', $retrievedUser->email)); app('log')->debug(sprintf('Result of getting user from provider: %s', $retrievedUser->email));
$this->user = $retrievedUser; $this->user = $retrievedUser;
} }
public function guest(): bool public function guest(): bool
@@ -139,14 +139,14 @@ class RemoteUserGuard implements Guard
/** /**
* @SuppressWarnings(PHPMD.ShortMethodName) * @SuppressWarnings(PHPMD.ShortMethodName)
*/ */
public function id(): null | int | string public function id(): null|int|string
{ {
app('log')->debug(sprintf('Now at %s', __METHOD__)); app('log')->debug(sprintf('Now at %s', __METHOD__));
return $this->user?->id; return $this->user?->id;
} }
public function setUser(null | Authenticatable | User $user): void // @phpstan-ignore-line public function setUser(null|Authenticatable|User $user): void // @phpstan-ignore-line
{ {
app('log')->debug(sprintf('Now at %s', __METHOD__)); app('log')->debug(sprintf('Now at %s', __METHOD__));
if ($user instanceof User) { if ($user instanceof User) {

View File

@@ -30,15 +30,13 @@ use FireflyIII\Models\Role;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Contracts\Auth\UserProvider;
use Override;
use Str;
/** /**
* Class RemoteUserProvider * Class RemoteUserProvider
*/ */
class RemoteUserProvider implements UserProvider class RemoteUserProvider implements UserProvider
{ {
#[Override] #[\Override]
public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false): void public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false): void
{ {
app('log')->debug(sprintf('Now at %s', __METHOD__)); app('log')->debug(sprintf('Now at %s', __METHOD__));
@@ -74,7 +72,7 @@ class RemoteUserProvider implements UserProvider
'blocked' => false, 'blocked' => false,
'blocked_code' => null, 'blocked_code' => null,
'email' => $identifier, 'email' => $identifier,
'password' => bcrypt(Str::random(64)), 'password' => bcrypt(\Str::random(64)),
] ]
); );
// if this is the first user, give them admin as well. // if this is the first user, give them admin as well.

View File

@@ -48,18 +48,19 @@ class Balance
return $cache->get(); return $cache->get();
} }
$query = Transaction::whereIn('transactions.account_id', $accounts->pluck('id')->toArray()) $query = Transaction::whereIn('transactions.account_id', $accounts->pluck('id')->toArray())
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->orderBy('transaction_journals.date', 'desc') ->orderBy('transaction_journals.date', 'desc')
->orderBy('transaction_journals.order', 'asc') ->orderBy('transaction_journals.order', 'asc')
->orderBy('transaction_journals.description', 'desc') ->orderBy('transaction_journals.description', 'desc')
->orderBy('transactions.amount', 'desc') ->orderBy('transactions.amount', 'desc')
->where('transaction_journals.date', '<=', $date); ->where('transaction_journals.date', '<=', $date)
;
$result = $query->get(['transactions.account_id', 'transactions.transaction_currency_id', 'transactions.balance_after']); $result = $query->get(['transactions.account_id', 'transactions.transaction_currency_id', 'transactions.balance_after']);
foreach ($result as $entry) { foreach ($result as $entry) {
$accountId = (int) $entry->account_id; $accountId = (int) $entry->account_id;
$currencyId = (int) $entry->transaction_currency_id; $currencyId = (int) $entry->transaction_currency_id;
$currencies[$currencyId] ??= TransactionCurrency::find($currencyId); $currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$return[$accountId] ??= []; $return[$accountId] ??= [];
if (array_key_exists($currencyId, $return[$accountId])) { if (array_key_exists($currencyId, $return[$accountId])) {

View File

@@ -43,21 +43,23 @@ class AccountList implements BinderInterface
if ('allAssetAccounts' === $value) { if ('allAssetAccounts' === $value) {
/** @var Collection $collection */ /** @var Collection $collection */
$collection = auth()->user()->accounts() $collection = auth()->user()->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]) ->whereIn('account_types.type', [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE])
->orderBy('accounts.name', 'ASC') ->orderBy('accounts.name', 'ASC')
->get(['accounts.*']); ->get(['accounts.*'])
;
} }
if ('allAssetAccounts' !== $value) { if ('allAssetAccounts' !== $value) {
$incoming = array_map('\intval', explode(',', $value)); $incoming = array_map('\intval', explode(',', $value));
$list = array_merge(array_unique($incoming), [0]); $list = array_merge(array_unique($incoming), [0]);
/** @var Collection $collection */ /** @var Collection $collection */
$collection = auth()->user()->accounts() $collection = auth()->user()->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') ->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('accounts.id', $list) ->whereIn('accounts.id', $list)
->orderBy('accounts.name', 'ASC') ->orderBy('accounts.name', 'ASC')
->get(['accounts.*']); ->get(['accounts.*'])
;
} }
if ($collection->count() > 0) { if ($collection->count() > 0) {

View File

@@ -41,12 +41,13 @@ class BudgetList implements BinderInterface
if (auth()->check()) { if (auth()->check()) {
if ('allBudgets' === $value) { if ('allBudgets' === $value) {
return auth()->user()->budgets()->where('active', true) return auth()->user()->budgets()->where('active', true)
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('name', 'ASC') ->orderBy('name', 'ASC')
->get(); ->get()
;
} }
$list = array_unique(array_map('\intval', explode(',', $value))); $list = array_unique(array_map('\intval', explode(',', $value)));
if (0 === count($list)) { // @phpstan-ignore-line if (0 === count($list)) { // @phpstan-ignore-line
app('log')->warning('Budget list count is zero, return 404.'); app('log')->warning('Budget list count is zero, return 404.');
@@ -56,9 +57,10 @@ class BudgetList implements BinderInterface
/** @var Collection $collection */ /** @var Collection $collection */
$collection = auth()->user()->budgets() $collection = auth()->user()->budgets()
->where('active', true) ->where('active', true)
->whereIn('id', $list) ->whereIn('id', $list)
->get(); ->get()
;
// add empty budget if applicable. // add empty budget if applicable.
if (in_array(0, $list, true)) { if (in_array(0, $list, true)) {

View File

@@ -41,19 +41,21 @@ class CategoryList implements BinderInterface
if (auth()->check()) { if (auth()->check()) {
if ('allCategories' === $value) { if ('allCategories' === $value) {
return auth()->user()->categories() return auth()->user()->categories()
->orderBy('name', 'ASC') ->orderBy('name', 'ASC')
->get(); ->get()
;
} }
$list = array_unique(array_map('\intval', explode(',', $value))); $list = array_unique(array_map('\intval', explode(',', $value)));
if (0 === count($list)) { // @phpstan-ignore-line if (0 === count($list)) { // @phpstan-ignore-line
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }
/** @var Collection $collection */ /** @var Collection $collection */
$collection = auth()->user()->categories() $collection = auth()->user()->categories()
->whereIn('id', $list) ->whereIn('id', $list)
->get(); ->get()
;
// add empty category if applicable. // add empty category if applicable.
if (in_array(0, $list, true)) { if (in_array(0, $list, true)) {

View File

@@ -43,16 +43,16 @@ class Date implements BinderInterface
/** @var FiscalHelperInterface $fiscalHelper */ /** @var FiscalHelperInterface $fiscalHelper */
$fiscalHelper = app(FiscalHelperInterface::class); $fiscalHelper = app(FiscalHelperInterface::class);
$magicWords = [ $magicWords = [
'currentMonthStart' => today(config('app.timezone'))->startOfMonth(), 'currentMonthStart' => today(config('app.timezone'))->startOfMonth(),
'currentMonthEnd' => today(config('app.timezone'))->endOfMonth(), 'currentMonthEnd' => today(config('app.timezone'))->endOfMonth(),
'currentYearStart' => today(config('app.timezone'))->startOfYear(), 'currentYearStart' => today(config('app.timezone'))->startOfYear(),
'currentYearEnd' => today(config('app.timezone'))->endOfYear(), 'currentYearEnd' => today(config('app.timezone'))->endOfYear(),
'previousMonthStart' => today(config('app.timezone'))->startOfMonth()->subDay()->startOfMonth(), 'previousMonthStart' => today(config('app.timezone'))->startOfMonth()->subDay()->startOfMonth(),
'previousMonthEnd' => today(config('app.timezone'))->startOfMonth()->subDay()->endOfMonth(), 'previousMonthEnd' => today(config('app.timezone'))->startOfMonth()->subDay()->endOfMonth(),
'previousYearStart' => today(config('app.timezone'))->startOfYear()->subDay()->startOfYear(), 'previousYearStart' => today(config('app.timezone'))->startOfYear()->subDay()->startOfYear(),
'previousYearEnd' => today(config('app.timezone'))->startOfYear()->subDay()->endOfYear(), 'previousYearEnd' => today(config('app.timezone'))->startOfYear()->subDay()->endOfYear(),
'currentFiscalYearStart' => $fiscalHelper->startOfFiscalYear(today(config('app.timezone'))), 'currentFiscalYearStart' => $fiscalHelper->startOfFiscalYear(today(config('app.timezone'))),
'currentFiscalYearEnd' => $fiscalHelper->endOfFiscalYear(today(config('app.timezone'))), 'currentFiscalYearEnd' => $fiscalHelper->endOfFiscalYear(today(config('app.timezone'))),
@@ -68,7 +68,7 @@ class Date implements BinderInterface
try { try {
$result = new Carbon($value); $result = new Carbon($value);
} catch (InvalidDateException | InvalidFormatException $e) { // @phpstan-ignore-line } catch (InvalidDateException|InvalidFormatException $e) { // @phpstan-ignore-line
$message = sprintf('Could not parse date "%s" for user #%d: %s', $value, auth()->user()->id, $e->getMessage()); $message = sprintf('Could not parse date "%s" for user #%d: %s', $value, auth()->user()->id, $e->getMessage());
app('log')->error($message); app('log')->error($message);

View File

@@ -39,7 +39,7 @@ class JournalList implements BinderInterface
public static function routeBinder(string $value, Route $route): array public static function routeBinder(string $value, Route $route): array
{ {
if (auth()->check()) { if (auth()->check()) {
$list = self::parseList($value); $list = self::parseList($value);
// get the journals by using the collector. // get the journals by using the collector.
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
@@ -47,7 +47,7 @@ class JournalList implements BinderInterface
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::RECONCILIATION]); $collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::RECONCILIATION]);
$collector->withCategoryInformation()->withBudgetInformation()->withTagInformation()->withAccountInformation(); $collector->withCategoryInformation()->withBudgetInformation()->withTagInformation()->withAccountInformation();
$collector->setJournalIds($list); $collector->setJournalIds($list);
$result = $collector->getExtractedJournals(); $result = $collector->getExtractedJournals();
if (0 === count($result)) { if (0 === count($result)) {
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }

View File

@@ -43,10 +43,11 @@ class TagList implements BinderInterface
if (auth()->check()) { if (auth()->check()) {
if ('allTags' === $value) { if ('allTags' === $value) {
return auth()->user()->tags() return auth()->user()->tags()
->orderBy('tag', 'ASC') ->orderBy('tag', 'ASC')
->get(); ->get()
;
} }
$list = array_unique(array_map('\strtolower', explode(',', $value))); $list = array_unique(array_map('\strtolower', explode(',', $value)));
app('log')->debug('List of tags is', $list); app('log')->debug('List of tags is', $list);
if (0 === count($list)) { // @phpstan-ignore-line if (0 === count($list)) { // @phpstan-ignore-line
@@ -58,7 +59,7 @@ class TagList implements BinderInterface
/** @var TagRepositoryInterface $repository */ /** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class); $repository = app(TagRepositoryInterface::class);
$repository->setUser(auth()->user()); $repository->setUser(auth()->user());
$allTags = $repository->get(); $allTags = $repository->get();
$collection = $allTags->filter( $collection = $allTags->filter(
static function (Tag $tag) use ($list) { static function (Tag $tag) use ($list) {

View File

@@ -40,7 +40,7 @@ class TagOrId implements BinderInterface
$repository = app(TagRepositoryInterface::class); $repository = app(TagRepositoryInterface::class);
$repository->setUser(auth()->user()); $repository->setUser(auth()->user());
$result = $repository->findByTag($value); $result = $repository->findByTag($value);
if (null === $result) { if (null === $result) {
$result = $repository->find((int) $value); $result = $repository->find((int) $value);
} }

View File

@@ -42,8 +42,9 @@ class UserGroupAccount implements BinderInterface
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$account = Account::where('id', (int) $value) $account = Account::where('id', (int) $value)
->where('user_group_id', $user->user_group_id) ->where('user_group_id', $user->user_group_id)
->first(); ->first()
;
if (null !== $account) { if (null !== $account) {
return $account; return $account;
} }

View File

@@ -42,8 +42,9 @@ class UserGroupBill implements BinderInterface
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$currency = Bill::where('id', (int) $value) $currency = Bill::where('id', (int) $value)
->where('user_group_id', $user->user_group_id) ->where('user_group_id', $user->user_group_id)
->first(); ->first()
;
if (null !== $currency) { if (null !== $currency) {
return $currency; return $currency;
} }

View File

@@ -39,8 +39,9 @@ class UserGroupExchangeRate implements BinderInterface
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$rate = CurrencyExchangeRate::where('id', (int) $value) $rate = CurrencyExchangeRate::where('id', (int) $value)
->where('user_group_id', $user->user_group_id) ->where('user_group_id', $user->user_group_id)
->first(); ->first()
;
if (null !== $rate) { if (null !== $rate) {
return $rate; return $rate;
} }

View File

@@ -39,8 +39,9 @@ class UserGroupTransaction implements BinderInterface
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$group = TransactionGroup::where('id', (int) $value) $group = TransactionGroup::where('id', (int) $value)
->where('user_group_id', $user->user_group_id) ->where('user_group_id', $user->user_group_id)
->first(); ->first()
;
if (null !== $group) { if (null !== $group) {
return $group; return $group;
} }

View File

@@ -23,9 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Support; namespace FireflyIII\Support;
use Cache;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use JsonException;
/** /**
* Class CacheProperties. * Class CacheProperties.
@@ -57,7 +55,7 @@ class CacheProperties
*/ */
public function get() public function get()
{ {
return Cache::get($this->hash); return \Cache::get($this->hash);
} }
public function getHash(): string public function getHash(): string
@@ -72,16 +70,16 @@ class CacheProperties
} }
$this->hash(); $this->hash();
return Cache::has($this->hash); return \Cache::has($this->hash);
} }
private function hash(): void private function hash(): void
{ {
$content = ''; $content = '';
foreach ($this->properties as $property) { foreach ($this->properties as $property) {
try { try {
$content .= json_encode($property, JSON_THROW_ON_ERROR); $content .= json_encode($property, JSON_THROW_ON_ERROR);
} catch (JsonException $e) { } catch (\JsonException $e) {
// @ignoreException // @ignoreException
$content .= hash('sha256', (string) time()); $content .= hash('sha256', (string) time());
} }
@@ -94,6 +92,6 @@ class CacheProperties
*/ */
public function store($data): void public function store($data): void
{ {
Cache::forever($this->hash, $data); \Cache::forever($this->hash, $data);
} }
} }

View File

@@ -26,16 +26,15 @@ namespace FireflyIII\Support\Calendar;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\IntervalException; use FireflyIII\Exceptions\IntervalException;
use SplObjectStorage;
/** /**
* Class Calculator * Class Calculator
*/ */
class Calculator class Calculator
{ {
public const int DEFAULT_INTERVAL = 1; public const int DEFAULT_INTERVAL = 1;
private static ?SplObjectStorage $intervalMap = null; private static ?\SplObjectStorage $intervalMap = null;
private static array $intervals = []; private static array $intervals = [];
/** /**
* @throws IntervalException * @throws IntervalException
@@ -66,14 +65,14 @@ class Calculator
/** /**
* @SuppressWarnings(PHPMD.MissingImport) * @SuppressWarnings(PHPMD.MissingImport)
*/ */
private static function loadIntervalMap(): SplObjectStorage private static function loadIntervalMap(): \SplObjectStorage
{ {
if (null !== self::$intervalMap) { if (null !== self::$intervalMap) {
return self::$intervalMap; return self::$intervalMap;
} }
self::$intervalMap = new SplObjectStorage(); self::$intervalMap = new \SplObjectStorage();
foreach (Periodicity::cases() as $interval) { foreach (Periodicity::cases() as $interval) {
$periodicityClass = __NAMESPACE__ . "\\Periodicity\\{$interval->name}"; $periodicityClass = __NAMESPACE__."\\Periodicity\\{$interval->name}";
self::$intervals[] = $interval->name; self::$intervals[] = $interval->name;
self::$intervalMap->attach($interval, new $periodicityClass()); self::$intervalMap->attach($interval, new $periodicityClass());
} }

View File

@@ -155,7 +155,7 @@ class FrontpageChartGenerator
*/ */
private function processRow(array $data, Budget $budget, BudgetLimit $limit, array $entry): array private function processRow(array $data, Budget $budget, BudgetLimit $limit, array $entry): array
{ {
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']); $title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
if ($limit->start_date->startOfDay()->ne($this->start->startOfDay()) || $limit->end_date->startOfDay()->ne($this->end->startOfDay())) { if ($limit->start_date->startOfDay()->ne($this->start->startOfDay()) || $limit->end_date->startOfDay()->ne($this->end->startOfDay())) {
$title = sprintf( $title = sprintf(
'%s (%s) (%s - %s)', '%s (%s) (%s - %s)',
@@ -165,7 +165,7 @@ class FrontpageChartGenerator
$limit->end_date->isoFormat($this->monthAndDayFormat) $limit->end_date->isoFormat($this->monthAndDayFormat)
); );
} }
$sumSpent = bcmul($entry['sum'], '-1'); // spent $sumSpent = bcmul($entry['sum'], '-1'); // spent
$data[0]['entries'][$title] = 1 === bccomp($sumSpent, $limit->amount) ? $limit->amount : $sumSpent; // spent $data[0]['entries'][$title] = 1 === bccomp($sumSpent, $limit->amount) ? $limit->amount : $sumSpent; // spent
$data[1]['entries'][$title] = 1 === bccomp($limit->amount, $sumSpent) ? bcadd($entry['sum'], $limit->amount) : '0'; // left to spent $data[1]['entries'][$title] = 1 === bccomp($limit->amount, $sumSpent) ? bcadd($entry['sum'], $limit->amount) : '0'; // left to spent

View File

@@ -65,13 +65,13 @@ class FrontpageChartGenerator
public function generate(): array public function generate(): array
{ {
$categories = $this->repository->getCategories(); $categories = $this->repository->getCategories();
$accounts = $this->accountRepos->getAccountsByType( $accounts = $this->accountRepos->getAccountsByType(
[AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT] [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT]
); );
// get expenses + income per category: // get expenses + income per category:
$collection = []; $collection = [];
/** @var Category $category */ /** @var Category $category */
foreach ($categories as $category) { foreach ($categories as $category) {
@@ -82,10 +82,10 @@ class FrontpageChartGenerator
// collect for no-category: // collect for no-category:
$collection[] = $this->collectNoCatExpenses($accounts); $collection[] = $this->collectNoCatExpenses($accounts);
$tempData = array_merge(...$collection); $tempData = array_merge(...$collection);
// sort temp array by amount. // sort temp array by amount.
$amounts = array_column($tempData, 'sum_float'); $amounts = array_column($tempData, 'sum_float');
array_multisort($amounts, SORT_ASC, $tempData); array_multisort($amounts, SORT_ASC, $tempData);
$currencyData = $this->createCurrencyGroups($tempData); $currencyData = $this->createCurrencyGroups($tempData);

View File

@@ -38,22 +38,22 @@ class WholePeriodChartGenerator
{ {
public function generate(Category $category, Carbon $start, Carbon $end): array public function generate(Category $category, Carbon $start, Carbon $end): array
{ {
$collection = new Collection([$category]); $collection = new Collection([$category]);
/** @var OperationsRepositoryInterface $opsRepository */ /** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class); $opsRepository = app(OperationsRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */ /** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class); $accountRepository = app(AccountRepositoryInterface::class);
$types = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]; $types = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
$accounts = $accountRepository->getAccountsByType($types); $accounts = $accountRepository->getAccountsByType($types);
$step = $this->calculateStep($start, $end); $step = $this->calculateStep($start, $end);
$chartData = []; $chartData = [];
$spent = []; $spent = [];
$earned = []; $earned = [];
$current = clone $start; $current = clone $start;
while ($current <= $end) { while ($current <= $end) {
$key = $current->format('Y-m-d'); $key = $current->format('Y-m-d');
@@ -63,14 +63,14 @@ class WholePeriodChartGenerator
$current = app('navigation')->addPeriod($current, $step, 0); $current = app('navigation')->addPeriod($current, $step, 0);
} }
$currencies = $this->extractCurrencies($spent) + $this->extractCurrencies($earned); $currencies = $this->extractCurrencies($spent) + $this->extractCurrencies($earned);
// generate chart data (for each currency) // generate chart data (for each currency)
/** @var array $currency */ /** @var array $currency */
foreach ($currencies as $currency) { foreach ($currencies as $currency) {
$code = $currency['currency_code']; $code = $currency['currency_code'];
$name = $currency['currency_name']; $name = $currency['currency_name'];
$chartData[sprintf('spent-in-%s', $code)] = [ $chartData[sprintf('spent-in-%s', $code)] = [
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $name]), 'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $name]),
'entries' => [], 'entries' => [],
'type' => 'bar', 'type' => 'bar',
@@ -85,11 +85,11 @@ class WholePeriodChartGenerator
]; ];
} }
$current = clone $start; $current = clone $start;
while ($current <= $end) { while ($current <= $end) {
$key = $current->format('Y-m-d'); $key = $current->format('Y-m-d');
$label = app('navigation')->periodShow($current, $step); $label = app('navigation')->periodShow($current, $step);
/** @var array $currency */ /** @var array $currency */
foreach ($currencies as $currency) { foreach ($currencies as $currency) {

View File

@@ -46,7 +46,7 @@ class ChartData
if (array_key_exists('native_currency_id', $data)) { if (array_key_exists('native_currency_id', $data)) {
$data['native_currency_id'] = (string) $data['native_currency_id']; $data['native_currency_id'] = (string) $data['native_currency_id'];
} }
$required = ['start', 'date', 'end', 'entries', 'native_entries']; $required = ['start', 'date', 'end', 'entries', 'native_entries'];
foreach ($required as $field) { foreach ($required as $field) {
if (!array_key_exists($field, $data)) { if (!array_key_exists($field, $data)) {
throw new FireflyException(sprintf('Data-set is missing the "%s"-variable.', $field)); throw new FireflyException(sprintf('Data-set is missing the "%s"-variable.', $field));

View File

@@ -55,7 +55,7 @@ class ChartColour
public static function getColour(int $index): string public static function getColour(int $index): string
{ {
$index %= count(self::$colours); $index %= count(self::$colours);
$row = self::$colours[$index]; $row = self::$colours[$index];
return sprintf('rgba(%d, %d, %d, 0.7)', $row[0], $row[1], $row[2]); return sprintf('rgba(%d, %d, %d, 0.7)', $row[0], $row[1], $row[2]);
} }

View File

@@ -68,7 +68,7 @@ class AutoBudgetCronjob extends AbstractCronjob
app('log')->info(sprintf('Will now fire auto budget cron job task for date "%s".', $this->date->format('Y-m-d'))); app('log')->info(sprintf('Will now fire auto budget cron job task for date "%s".', $this->date->format('Y-m-d')));
/** @var CreateAutoBudgetLimits $job */ /** @var CreateAutoBudgetLimits $job */
$job = app(CreateAutoBudgetLimits::class, [$this->date]); $job = app(CreateAutoBudgetLimits::class, [$this->date]);
$job->setDate($this->date); $job->setDate($this->date);
$job->handle(); $job->handle();

View File

@@ -80,7 +80,7 @@ class BillWarningCronjob extends AbstractCronjob
app('log')->info(sprintf('Will now fire bill warning job task for date "%s".', $this->date->format('Y-m-d H:i:s'))); app('log')->info(sprintf('Will now fire bill warning job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
/** @var WarnAboutBills $job */ /** @var WarnAboutBills $job */
$job = app(WarnAboutBills::class); $job = app(WarnAboutBills::class);
$job->setDate($this->date); $job->setDate($this->date);
$job->setForce($this->force); $job->setForce($this->force);
$job->handle(); $job->handle();

View File

@@ -69,7 +69,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
app('log')->info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d'))); app('log')->info(sprintf('Will now fire exchange rates cron job task for date "%s".', $this->date->format('Y-m-d')));
/** @var DownloadExchangeRates $job */ /** @var DownloadExchangeRates $job */
$job = app(DownloadExchangeRates::class); $job = app(DownloadExchangeRates::class);
$job->setDate($this->date); $job->setDate($this->date);
$job->handle(); $job->handle();

View File

@@ -78,7 +78,7 @@ class RecurringCronjob extends AbstractCronjob
{ {
app('log')->info(sprintf('Will now fire recurring cron job task for date "%s".', $this->date->format('Y-m-d H:i:s'))); app('log')->info(sprintf('Will now fire recurring cron job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
$job = new CreateRecurringTransactions($this->date); $job = new CreateRecurringTransactions($this->date);
$job->setForce($this->force); $job->setForce($this->force);
$job->handle(); $job->handle();

View File

@@ -27,7 +27,6 @@ use Eloquent;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Form\FormSupport; use FireflyIII\Support\Form\FormSupport;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Throwable;
/** /**
* Class ExpandedForm. * Class ExpandedForm.
@@ -43,7 +42,7 @@ class ExpandedForm
*/ */
public function amountNoCurrency(string $name, $value = null, ?array $options = null): string public function amountNoCurrency(string $name, $value = null, ?array $options = null): string
{ {
$options ??= []; $options ??= [];
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
@@ -57,7 +56,7 @@ class ExpandedForm
// } // }
try { try {
$html = view('form.amount-no-currency', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.amount-no-currency', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Could not render amountNoCurrency(): %s', $e->getMessage())); app('log')->error(sprintf('Could not render amountNoCurrency(): %s', $e->getMessage()));
$html = 'Could not render amountNoCurrency.'; $html = 'Could not render amountNoCurrency.';
@@ -74,8 +73,8 @@ class ExpandedForm
*/ */
public function checkbox(string $name, ?int $value = null, $checked = null, ?array $options = null): string public function checkbox(string $name, ?int $value = null, $checked = null, ?array $options = null): string
{ {
$options ??= []; $options ??= [];
$value ??= 1; $value ??= 1;
$options['checked'] = true === $checked; $options['checked'] = true === $checked;
if (app('session')->has('preFilled')) { if (app('session')->has('preFilled')) {
@@ -83,16 +82,16 @@ class ExpandedForm
$options['checked'] = $preFilled[$name] ?? $options['checked']; $options['checked'] = $preFilled[$name] ?? $options['checked'];
} }
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value); $value = $this->fillFieldValue($name, $value);
unset($options['placeholder'], $options['autocomplete'], $options['class']); unset($options['placeholder'], $options['autocomplete'], $options['class']);
try { try {
$html = view('form.checkbox', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.checkbox', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render checkbox(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render checkbox(): %s', $e->getMessage()));
$html = 'Could not render checkbox.'; $html = 'Could not render checkbox.';
@@ -117,7 +116,7 @@ class ExpandedForm
try { try {
$html = view('form.date', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.date', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render date(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render date(): %s', $e->getMessage()));
$html = 'Could not render date.'; $html = 'Could not render date.';
@@ -139,7 +138,7 @@ class ExpandedForm
try { try {
$html = view('form.file', compact('classes', 'name', 'label', 'options'))->render(); $html = view('form.file', compact('classes', 'name', 'label', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render file(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render file(): %s', $e->getMessage()));
$html = 'Could not render file.'; $html = 'Could not render file.';
@@ -157,15 +156,15 @@ class ExpandedForm
public function integer(string $name, $value = null, ?array $options = null): string public function integer(string $name, $value = null, ?array $options = null): string
{ {
$options ??= []; $options ??= [];
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value); $value = $this->fillFieldValue($name, $value);
$options['step'] ??= '1'; $options['step'] ??= '1';
try { try {
$html = view('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render integer(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render integer(): %s', $e->getMessage()));
$html = 'Could not render integer.'; $html = 'Could not render integer.';
@@ -190,7 +189,7 @@ class ExpandedForm
try { try {
$html = view('form.location', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.location', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render location(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render location(): %s', $e->getMessage()));
$html = 'Could not render location.'; $html = 'Could not render location.';
@@ -206,12 +205,12 @@ class ExpandedForm
$selectList[0] = '(none)'; $selectList[0] = '(none)';
$fields = ['title', 'name', 'description']; $fields = ['title', 'name', 'description'];
/** @var Eloquent $entry */ /** @var \Eloquent $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
// All Eloquent models have an ID // All Eloquent models have an ID
$entryId = $entry->id; // @phpstan-ignore-line $entryId = $entry->id; // @phpstan-ignore-line
$current = $entry->toArray(); $current = $entry->toArray();
$title = null; $title = null;
foreach ($fields as $field) { foreach ($fields as $field) {
if (array_key_exists($field, $current) && null === $title) { if (array_key_exists($field, $current) && null === $title) {
$title = $current[$field]; $title = $current[$field];
@@ -243,7 +242,7 @@ class ExpandedForm
try { try {
$html = view('form.object_group', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.object_group', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render objectGroup(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render objectGroup(): %s', $e->getMessage()));
$html = 'Could not render objectGroup.'; $html = 'Could not render objectGroup.';
@@ -260,7 +259,7 @@ class ExpandedForm
{ {
try { try {
$html = view('form.options', compact('type', 'name'))->render(); $html = view('form.options', compact('type', 'name'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render select(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render select(): %s', $e->getMessage()));
$html = 'Could not render optionsList.'; $html = 'Could not render optionsList.';
@@ -281,7 +280,7 @@ class ExpandedForm
try { try {
$html = view('form.password', compact('classes', 'name', 'label', 'options'))->render(); $html = view('form.password', compact('classes', 'name', 'label', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render password(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render password(): %s', $e->getMessage()));
$html = 'Could not render password.'; $html = 'Could not render password.';
@@ -302,7 +301,7 @@ class ExpandedForm
try { try {
$html = view('form.password', compact('classes', 'value', 'name', 'label', 'options'))->render(); $html = view('form.password', compact('classes', 'value', 'name', 'label', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render passwordWithValue(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render passwordWithValue(): %s', $e->getMessage()));
$html = 'Could not render passwordWithValue.'; $html = 'Could not render passwordWithValue.';
@@ -330,7 +329,7 @@ class ExpandedForm
try { try {
$html = view('form.percentage', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.percentage', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render percentage(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render percentage(): %s', $e->getMessage()));
$html = 'Could not render percentage.'; $html = 'Could not render percentage.';
@@ -353,7 +352,7 @@ class ExpandedForm
try { try {
$html = view('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render staticText(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render staticText(): %s', $e->getMessage()));
$html = 'Could not render staticText.'; $html = 'Could not render staticText.';
@@ -377,7 +376,7 @@ class ExpandedForm
try { try {
$html = view('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render text(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render text(): %s', $e->getMessage()));
$html = 'Could not render text.'; $html = 'Could not render text.';
@@ -406,7 +405,7 @@ class ExpandedForm
try { try {
$html = view('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render textarea(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render textarea(): %s', $e->getMessage()));
$html = 'Could not render textarea.'; $html = 'Could not render textarea.';

View File

@@ -82,8 +82,8 @@ class ExportDataGenerator
public function __construct() public function __construct()
{ {
$this->accounts = new Collection(); $this->accounts = new Collection();
$this->start = today(config('app.timezone')); $this->start = today(config('app.timezone'));
$this->start->subYear(); $this->start->subYear();
$this->end = today(config('app.timezone')); $this->end = today(config('app.timezone'));
$this->exportTransactions = false; $this->exportTransactions = false;
@@ -141,7 +141,7 @@ class ExportDataGenerator
*/ */
private function exportAccounts(): string private function exportAccounts(): string
{ {
$header = [ $header = [
'user_id', 'user_id',
'account_id', 'account_id',
'created_at', 'created_at',
@@ -162,7 +162,7 @@ class ExportDataGenerator
]; ];
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$allAccounts = $repository->getAccountsByType([]); $allAccounts = $repository->getAccountsByType([]);
$records = []; $records = [];
@@ -192,7 +192,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -230,8 +230,8 @@ class ExportDataGenerator
/** @var BillRepositoryInterface $repository */ /** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class); $repository = app(BillRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$bills = $repository->getBills(); $bills = $repository->getBills();
$header = [ $header = [
'user_id', 'user_id',
'bill_id', 'bill_id',
'created_at', 'created_at',
@@ -245,7 +245,7 @@ class ExportDataGenerator
'skip', 'skip',
'active', 'active',
]; ];
$records = []; $records = [];
/** @var Bill $bill */ /** @var Bill $bill */
foreach ($bills as $bill) { foreach ($bills as $bill) {
@@ -266,7 +266,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -296,7 +296,7 @@ class ExportDataGenerator
*/ */
private function exportBudgets(): string private function exportBudgets(): string
{ {
$header = [ $header = [
'user_id', 'user_id',
'budget_id', 'budget_id',
'name', 'name',
@@ -310,9 +310,9 @@ class ExportDataGenerator
$budgetRepos = app(BudgetRepositoryInterface::class); $budgetRepos = app(BudgetRepositoryInterface::class);
$budgetRepos->setUser($this->user); $budgetRepos->setUser($this->user);
$limitRepos = app(BudgetLimitRepositoryInterface::class); $limitRepos = app(BudgetLimitRepositoryInterface::class);
$budgets = $budgetRepos->getBudgets(); $budgets = $budgetRepos->getBudgets();
$records = []; $records = [];
/** @var Budget $budget */ /** @var Budget $budget */
foreach ($budgets as $budget) { foreach ($budgets as $budget) {
@@ -335,7 +335,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -365,10 +365,10 @@ class ExportDataGenerator
*/ */
private function exportCategories(): string private function exportCategories(): string
{ {
$header = ['user_id', 'category_id', 'created_at', 'updated_at', 'name']; $header = ['user_id', 'category_id', 'created_at', 'updated_at', 'name'];
/** @var CategoryRepositoryInterface $catRepos */ /** @var CategoryRepositoryInterface $catRepos */
$catRepos = app(CategoryRepositoryInterface::class); $catRepos = app(CategoryRepositoryInterface::class);
$catRepos->setUser($this->user); $catRepos->setUser($this->user);
$records = []; $records = [];
@@ -386,7 +386,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -417,14 +417,14 @@ class ExportDataGenerator
private function exportPiggies(): string private function exportPiggies(): string
{ {
/** @var PiggyBankRepositoryInterface $piggyRepos */ /** @var PiggyBankRepositoryInterface $piggyRepos */
$piggyRepos = app(PiggyBankRepositoryInterface::class); $piggyRepos = app(PiggyBankRepositoryInterface::class);
$piggyRepos->setUser($this->user); $piggyRepos->setUser($this->user);
/** @var AccountRepositoryInterface $accountRepos */ /** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class); $accountRepos = app(AccountRepositoryInterface::class);
$accountRepos->setUser($this->user); $accountRepos->setUser($this->user);
$header = [ $header = [
'user_id', 'user_id',
'piggy_bank_id', 'piggy_bank_id',
'created_at', 'created_at',
@@ -440,8 +440,8 @@ class ExportDataGenerator
'order', 'order',
'active', 'active',
]; ];
$records = []; $records = [];
$piggies = $piggyRepos->getPiggyBanks(); $piggies = $piggyRepos->getPiggyBanks();
/** @var PiggyBank $piggy */ /** @var PiggyBank $piggy */
foreach ($piggies as $piggy) { foreach ($piggies as $piggy) {
@@ -466,7 +466,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -499,7 +499,7 @@ class ExportDataGenerator
/** @var RecurringRepositoryInterface $recurringRepos */ /** @var RecurringRepositoryInterface $recurringRepos */
$recurringRepos = app(RecurringRepositoryInterface::class); $recurringRepos = app(RecurringRepositoryInterface::class);
$recurringRepos->setUser($this->user); $recurringRepos->setUser($this->user);
$header = [ $header = [
// recurrence: // recurrence:
'user_id', 'recurrence_id', 'row_contains', 'created_at', 'updated_at', 'type', 'title', 'description', 'first_date', 'repeat_until', 'latest_date', 'repetitions', 'apply_rules', 'active', 'user_id', 'recurrence_id', 'row_contains', 'created_at', 'updated_at', 'type', 'title', 'description', 'first_date', 'repeat_until', 'latest_date', 'repetitions', 'apply_rules', 'active',
@@ -508,8 +508,8 @@ class ExportDataGenerator
// transactions + meta: // transactions + meta:
'currency_code', 'foreign_currency_code', 'source_name', 'source_type', 'destination_name', 'destination_type', 'amount', 'foreign_amount', 'category', 'budget', 'piggy_bank', 'tags', 'currency_code', 'foreign_currency_code', 'source_name', 'source_type', 'destination_name', 'destination_type', 'amount', 'foreign_amount', 'category', 'budget', 'piggy_bank', 'tags',
]; ];
$records = []; $records = [];
$recurrences = $recurringRepos->getAll(); $recurrences = $recurringRepos->getAll();
/** @var Recurrence $recurrence */ /** @var Recurrence $recurrence */
foreach ($recurrences as $recurrence) { foreach ($recurrences as $recurrence) {
@@ -542,7 +542,7 @@ class ExportDataGenerator
$piggyBankId = $recurringRepos->getPiggyBank($transaction); $piggyBankId = $recurringRepos->getPiggyBank($transaction);
$tags = $recurringRepos->getTags($transaction); $tags = $recurringRepos->getTags($transaction);
$records[] = [ $records[] = [
// recurrence // recurrence
$this->user->id, $this->user->id,
$recurrence->id, $recurrence->id,
@@ -558,7 +558,7 @@ class ExportDataGenerator
} }
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -595,8 +595,8 @@ class ExportDataGenerator
'action_type', 'action_value', 'action_order', 'action_active', 'action_stop_processing']; 'action_type', 'action_value', 'action_order', 'action_active', 'action_stop_processing'];
$ruleRepos = app(RuleRepositoryInterface::class); $ruleRepos = app(RuleRepositoryInterface::class);
$ruleRepos->setUser($this->user); $ruleRepos->setUser($this->user);
$rules = $ruleRepos->getAll(); $rules = $ruleRepos->getAll();
$records = []; $records = [];
/** @var Rule $rule */ /** @var Rule $rule */
foreach ($rules as $rule) { foreach ($rules as $rule) {
@@ -635,7 +635,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -665,12 +665,12 @@ class ExportDataGenerator
*/ */
private function exportTags(): string private function exportTags(): string
{ {
$header = ['user_id', 'tag_id', 'created_at', 'updated_at', 'tag', 'date', 'description', 'latitude', 'longitude', 'zoom_level']; $header = ['user_id', 'tag_id', 'created_at', 'updated_at', 'tag', 'date', 'description', 'latitude', 'longitude', 'zoom_level'];
$tagRepos = app(TagRepositoryInterface::class); $tagRepos = app(TagRepositoryInterface::class);
$tagRepos->setUser($this->user); $tagRepos->setUser($this->user);
$tags = $tagRepos->get(); $tags = $tagRepos->get();
$records = []; $records = [];
/** @var Tag $tag */ /** @var Tag $tag */
foreach ($tags as $tag) { foreach ($tags as $tag) {
@@ -689,7 +689,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {
@@ -728,26 +728,27 @@ class ExportDataGenerator
private function exportTransactions(): string private function exportTransactions(): string
{ {
// TODO better place for keys? // TODO better place for keys?
$header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'amount', 'foreign_amount', 'currency_code', 'foreign_currency_code', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes']; $header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'amount', 'foreign_amount', 'currency_code', 'foreign_currency_code', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban', 'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes'];
$metaFields = config('firefly.journal_meta_fields'); $metaFields = config('firefly.journal_meta_fields');
$header = array_merge($header, $metaFields); $header = array_merge($header, $metaFields);
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user); $collector->setUser($this->user);
$collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation() $collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()
->withBudgetInformation()->withTagInformation()->withNotes(); ->withBudgetInformation()->withTagInformation()->withNotes()
;
if (0 !== $this->accounts->count()) { if (0 !== $this->accounts->count()) {
$collector->setAccounts($this->accounts); $collector->setAccounts($this->accounts);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
// get repository for meta data: // get repository for meta data:
$repository = app(TransactionGroupRepositoryInterface::class); $repository = app(TransactionGroupRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$records = []; $records = [];
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
@@ -772,7 +773,7 @@ class ExportDataGenerator
} }
// load the CSV document from a string // load the CSV document from a string
$csv = Writer::createFromString(); $csv = Writer::createFromString();
// insert the header // insert the header
try { try {

View File

@@ -23,8 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Support; namespace FireflyIII\Support;
use Cache;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Configuration; use FireflyIII\Models\Configuration;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\DecryptException;
@@ -39,9 +37,9 @@ class FireflyConfig
{ {
public function delete(string $name): void public function delete(string $name): void
{ {
$fullName = 'ff-config-' . $name; $fullName = 'ff-config-'.$name;
if (Cache::has($fullName)) { if (\Cache::has($fullName)) {
Cache::forget($fullName); \Cache::forget($fullName);
} }
Configuration::where('name', $name)->forceDelete(); Configuration::where('name', $name)->forceDelete();
} }
@@ -81,20 +79,20 @@ class FireflyConfig
*/ */
public function get(string $name, $default = null): ?Configuration public function get(string $name, $default = null): ?Configuration
{ {
$fullName = 'ff-config-' . $name; $fullName = 'ff-config-'.$name;
if (Cache::has($fullName)) { if (\Cache::has($fullName)) {
return Cache::get($fullName); return \Cache::get($fullName);
} }
try { try {
/** @var null|Configuration $config */ /** @var null|Configuration $config */
$config = Configuration::where('name', $name)->first(['id', 'name', 'data']); $config = Configuration::where('name', $name)->first(['id', 'name', 'data']);
} catch (Exception | QueryException $e) { } catch (\Exception|QueryException $e) {
throw new FireflyException(sprintf('Could not poll the database: %s', $e->getMessage()), 0, $e); throw new FireflyException(sprintf('Could not poll the database: %s', $e->getMessage()), 0, $e);
} }
if (null !== $config) { if (null !== $config) {
Cache::forever($fullName, $config); \Cache::forever($fullName, $config);
return $config; return $config;
} }
@@ -124,13 +122,13 @@ class FireflyConfig
$item->name = $name; $item->name = $name;
$item->data = $value; $item->data = $value;
$item->save(); $item->save();
Cache::forget('ff-config-' . $name); \Cache::forget('ff-config-'.$name);
return $item; return $item;
} }
$config->data = $value; $config->data = $value;
$config->save(); $config->save();
Cache::forget('ff-config-' . $name); \Cache::forget('ff-config-'.$name);
return $config; return $config;
} }

View File

@@ -29,7 +29,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Throwable;
/** /**
* Class AccountForm * Class AccountForm
@@ -69,7 +68,7 @@ class AccountForm
/** @var Account $account */ /** @var Account $account */
foreach ($accountList as $account) { foreach ($accountList as $account) {
$role = (string) $repository->getMetaValue($account, 'account_role'); $role = (string) $repository->getMetaValue($account, 'account_role');
if (in_array($account->accountType->type, $liabilityTypes, true)) { if (in_array($account->accountType->type, $liabilityTypes, true)) {
$role = sprintf('l_%s', $account->accountType->type); $role = sprintf('l_%s', $account->accountType->type);
} }
@@ -94,9 +93,9 @@ class AccountForm
*/ */
public function activeWithdrawalDestinations(string $name, mixed $value = null, ?array $options = null): string public function activeWithdrawalDestinations(string $name, mixed $value = null, ?array $options = null): string
{ {
$types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::EXPENSE]; $types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::EXPENSE];
$repository = $this->getAccountRepository(); $repository = $this->getAccountRepository();
$grouped = $this->getAccountsGrouped($types, $repository); $grouped = $this->getAccountsGrouped($types, $repository);
$cash = $repository->getCashAccount(); $cash = $repository->getCashAccount();
$key = (string) trans('firefly.cash_account_type'); $key = (string) trans('firefly.cash_account_type');
@@ -112,21 +111,21 @@ class AccountForm
*/ */
public function assetAccountCheckList(string $name, ?array $options = null): string public function assetAccountCheckList(string $name, ?array $options = null): string
{ {
$options ??= []; $options ??= [];
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
$selected = request()->old($name) ?? []; $selected = request()->old($name) ?? [];
// get all asset accounts: // get all asset accounts:
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]; $types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT];
$grouped = $this->getAccountsGrouped($types); $grouped = $this->getAccountsGrouped($types);
unset($options['class']); unset($options['class']);
try { try {
$html = view('form.assetAccountCheckList', compact('classes', 'selected', 'name', 'label', 'options', 'grouped'))->render(); $html = view('form.assetAccountCheckList', compact('classes', 'selected', 'name', 'label', 'options', 'grouped'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render assetAccountCheckList(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render assetAccountCheckList(): %s', $e->getMessage()));
$html = 'Could not render assetAccountCheckList.'; $html = 'Could not render assetAccountCheckList.';

View File

@@ -28,7 +28,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Throwable;
/** /**
* Class CurrencyForm * Class CurrencyForm
@@ -62,15 +61,15 @@ class CurrencyForm
$defaultCurrency = $options['currency'] ?? app('amount')->getDefaultCurrency(); $defaultCurrency = $options['currency'] ?? app('amount')->getDefaultCurrency();
/** @var Collection $currencies */ /** @var Collection $currencies */
$currencies = app('amount')->getCurrencies(); $currencies = app('amount')->getCurrencies();
unset($options['currency'], $options['placeholder']); unset($options['currency'], $options['placeholder']);
// perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount) // perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount)
$preFilled = session('preFilled'); $preFilled = session('preFilled');
if (!is_array($preFilled)) { if (!is_array($preFilled)) {
$preFilled = []; $preFilled = [];
} }
$key = 'amount_currency_id_' . $name; $key = 'amount_currency_id_'.$name;
$sentCurrencyId = array_key_exists($key, $preFilled) ? (int) $preFilled[$key] : $defaultCurrency->id; $sentCurrencyId = array_key_exists($key, $preFilled) ? (int) $preFilled[$key] : $defaultCurrency->id;
app('log')->debug(sprintf('Sent currency ID is %d', $sentCurrencyId)); app('log')->debug(sprintf('Sent currency ID is %d', $sentCurrencyId));
@@ -90,8 +89,8 @@ class CurrencyForm
} }
try { try {
$html = view('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.'.$view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render currencyField(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render currencyField(): %s', $e->getMessage()));
$html = 'Could not render currencyField.'; $html = 'Could not render currencyField.';
@@ -130,16 +129,16 @@ class CurrencyForm
$defaultCurrency = $options['currency'] ?? app('amount')->getDefaultCurrency(); $defaultCurrency = $options['currency'] ?? app('amount')->getDefaultCurrency();
/** @var Collection $currencies */ /** @var Collection $currencies */
$currencies = app('amount')->getAllCurrencies(); $currencies = app('amount')->getAllCurrencies();
unset($options['currency'], $options['placeholder']); unset($options['currency'], $options['placeholder']);
// perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount) // perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount)
$preFilled = session('preFilled'); $preFilled = session('preFilled');
if (!is_array($preFilled)) { if (!is_array($preFilled)) {
$preFilled = []; $preFilled = [];
} }
$key = 'amount_currency_id_' . $name; $key = 'amount_currency_id_'.$name;
$sentCurrencyId = array_key_exists($key, $preFilled) ? (int) $preFilled[$key] : $defaultCurrency->id; $sentCurrencyId = array_key_exists($key, $preFilled) ? (int) $preFilled[$key] : $defaultCurrency->id;
app('log')->debug(sprintf('Sent currency ID is %d', $sentCurrencyId)); app('log')->debug(sprintf('Sent currency ID is %d', $sentCurrencyId));
@@ -159,8 +158,8 @@ class CurrencyForm
} }
try { try {
$html = view('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render(); $html = view('form.'.$view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render currencyField(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render currencyField(): %s', $e->getMessage()));
$html = 'Could not render currencyField.'; $html = 'Could not render currencyField.';
@@ -181,12 +180,12 @@ class CurrencyForm
$currencyRepos = app(CurrencyRepositoryInterface::class); $currencyRepos = app(CurrencyRepositoryInterface::class);
// get all currencies: // get all currencies:
$list = $currencyRepos->get(); $list = $currencyRepos->get();
$array = []; $array = [];
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($list as $currency) { foreach ($list as $currency) {
$array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; $array[$currency->id] = $currency->name.' ('.$currency->symbol.')';
} }
return $this->select($name, $array, $value, $options); return $this->select($name, $array, $value, $options);
@@ -203,14 +202,14 @@ class CurrencyForm
$currencyRepos = app(CurrencyRepositoryInterface::class); $currencyRepos = app(CurrencyRepositoryInterface::class);
// get all currencies: // get all currencies:
$list = $currencyRepos->get(); $list = $currencyRepos->get();
$array = [ $array = [
0 => (string) trans('firefly.no_currency'), 0 => (string) trans('firefly.no_currency'),
]; ];
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($list as $currency) { foreach ($list as $currency) {
$array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')'; $array[$currency->id] = $currency->name.' ('.$currency->symbol.')';
} }
return $this->select($name, $array, $value, $options); return $this->select($name, $array, $value, $options);

View File

@@ -28,7 +28,6 @@ use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException; use Carbon\Exceptions\InvalidDateException;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Support\MessageBag; use Illuminate\Support\MessageBag;
use Throwable;
/** /**
* Trait FormSupport * Trait FormSupport
@@ -37,7 +36,7 @@ trait FormSupport
{ {
public function multiSelect(string $name, ?array $list = null, $selected = null, ?array $options = null): string public function multiSelect(string $name, ?array $list = null, $selected = null, ?array $options = null): string
{ {
$list ??= []; $list ??= [];
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
@@ -47,7 +46,7 @@ trait FormSupport
try { try {
$html = view('form.multi-select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render(); $html = view('form.multi-select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render multi-select(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render multi-select(): %s', $e->getMessage()));
$html = 'Could not render multi-select.'; $html = 'Could not render multi-select.';
} }
@@ -63,7 +62,7 @@ trait FormSupport
} }
$name = str_replace('[]', '', $name); $name = str_replace('[]', '', $name);
return (string) trans('form.' . $name); return (string) trans('form.'.$name);
} }
/** /**
@@ -71,10 +70,10 @@ trait FormSupport
*/ */
protected function expandOptionArray(string $name, $label, ?array $options = null): array protected function expandOptionArray(string $name, $label, ?array $options = null): array
{ {
$options ??= []; $options ??= [];
$name = str_replace('[]', '', $name); $name = str_replace('[]', '', $name);
$options['class'] = 'form-control'; $options['class'] = 'form-control';
$options['id'] = 'ffInput_' . $name; $options['id'] = 'ffInput_'.$name;
$options['autocomplete'] = 'off'; $options['autocomplete'] = 'off';
$options['placeholder'] = ucfirst($label); $options['placeholder'] = ucfirst($label);
@@ -123,7 +122,7 @@ trait FormSupport
*/ */
public function select(string $name, ?array $list = null, $selected = null, ?array $options = null): string public function select(string $name, ?array $list = null, $selected = null, ?array $options = null): string
{ {
$list ??= []; $list ??= [];
$label = $this->label($name, $options); $label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options); $options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name); $classes = $this->getHolderClasses($name);
@@ -132,7 +131,7 @@ trait FormSupport
try { try {
$html = view('form.select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render(); $html = view('form.select', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Could not render select(): %s', $e->getMessage())); app('log')->debug(sprintf('Could not render select(): %s', $e->getMessage()));
$html = 'Could not render select.'; $html = 'Could not render select.';
} }

View File

@@ -62,14 +62,14 @@ class PiggyBankForm
/** @var PiggyBank $piggy */ /** @var PiggyBank $piggy */
foreach ($piggyBanks as $piggy) { foreach ($piggyBanks as $piggy) {
$group = $piggy->objectGroups->first(); $group = $piggy->objectGroups->first();
$groupTitle = null; $groupTitle = null;
$groupOrder = 0; $groupOrder = 0;
if (null !== $group) { if (null !== $group) {
$groupTitle = $group->title; $groupTitle = $group->title;
$groupOrder = $group->order; $groupOrder = $group->order;
} }
$subList[$groupOrder] ??= [ $subList[$groupOrder] ??= [
'group' => [ 'group' => [
'title' => $groupTitle, 'title' => $groupTitle,
], ],

View File

@@ -41,8 +41,8 @@ class RuleForm
$groupRepos = app(RuleGroupRepositoryInterface::class); $groupRepos = app(RuleGroupRepositoryInterface::class);
// get all currencies: // get all currencies:
$list = $groupRepos->get(); $list = $groupRepos->get();
$array = []; $array = [];
/** @var RuleGroup $group */ /** @var RuleGroup $group */
foreach ($list as $group) { foreach ($list as $group) {
@@ -57,15 +57,15 @@ class RuleForm
*/ */
public function ruleGroupListWithEmpty(string $name, $value = null, ?array $options = null): string public function ruleGroupListWithEmpty(string $name, $value = null, ?array $options = null): string
{ {
$options ??= []; $options ??= [];
$options['class'] = 'form-control'; $options['class'] = 'form-control';
/** @var RuleGroupRepositoryInterface $groupRepos */ /** @var RuleGroupRepositoryInterface $groupRepos */
$groupRepos = app(RuleGroupRepositoryInterface::class); $groupRepos = app(RuleGroupRepositoryInterface::class);
// get all currencies: // get all currencies:
$list = $groupRepos->get(); $list = $groupRepos->get();
$array = [ $array = [
0 => (string) trans('firefly.none_in_select_list'), 0 => (string) trans('firefly.none_in_select_list'),
]; ];

View File

@@ -64,7 +64,7 @@ class AccountBalanceGrouped
/** @var array $currency */ /** @var array $currency */
foreach ($this->data as $currency) { foreach ($this->data as $currency) {
// income and expense array prepped: // income and expense array prepped:
$income = [ $income = [
'label' => 'earned', 'label' => 'earned',
'currency_id' => (string) $currency['currency_id'], 'currency_id' => (string) $currency['currency_id'],
'currency_symbol' => $currency['currency_symbol'], 'currency_symbol' => $currency['currency_symbol'],
@@ -81,7 +81,7 @@ class AccountBalanceGrouped
'entries' => [], 'entries' => [],
'native_entries' => [], 'native_entries' => [],
]; ];
$expense = [ $expense = [
'label' => 'spent', 'label' => 'spent',
'currency_id' => (string) $currency['currency_id'], 'currency_id' => (string) $currency['currency_id'],
'currency_symbol' => $currency['currency_symbol'], 'currency_symbol' => $currency['currency_symbol'],
@@ -101,22 +101,22 @@ class AccountBalanceGrouped
// loop all possible periods between $start and $end, and add them to the correct dataset. // loop all possible periods between $start and $end, and add them to the correct dataset.
$currentStart = clone $this->start; $currentStart = clone $this->start;
while ($currentStart <= $this->end) { while ($currentStart <= $this->end) {
$key = $currentStart->format($this->carbonFormat); $key = $currentStart->format($this->carbonFormat);
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
// normal entries // normal entries
$income['entries'][$label] = app('steam')->bcround($currency[$key]['earned'] ?? '0', $currency['currency_decimal_places']); $income['entries'][$label] = app('steam')->bcround($currency[$key]['earned'] ?? '0', $currency['currency_decimal_places']);
$expense['entries'][$label] = app('steam')->bcround($currency[$key]['spent'] ?? '0', $currency['currency_decimal_places']); $expense['entries'][$label] = app('steam')->bcround($currency[$key]['spent'] ?? '0', $currency['currency_decimal_places']);
// converted entries // converted entries
$income['native_entries'][$label] = app('steam')->bcround($currency[$key]['native_earned'] ?? '0', $currency['native_currency_decimal_places']); $income['native_entries'][$label] = app('steam')->bcround($currency[$key]['native_earned'] ?? '0', $currency['native_currency_decimal_places']);
$expense['native_entries'][$label] = app('steam')->bcround($currency[$key]['native_spent'] ?? '0', $currency['native_currency_decimal_places']); $expense['native_entries'][$label] = app('steam')->bcround($currency[$key]['native_spent'] ?? '0', $currency['native_currency_decimal_places']);
// next loop // next loop
$currentStart = app('navigation')->addPeriod($currentStart, $this->preferredRange, 0); $currentStart = app('navigation')->addPeriod($currentStart, $this->preferredRange, 0);
} }
$chartData[] = $income; $chartData[] = $income;
$chartData[] = $expense; $chartData[] = $expense;
} }
return $chartData; return $chartData;
@@ -142,9 +142,9 @@ class AccountBalanceGrouped
private function processJournal(array $journal): void private function processJournal(array $journal): void
{ {
// format the date according to the period // format the date according to the period
$period = $journal['date']->format($this->carbonFormat); $period = $journal['date']->format($this->carbonFormat);
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currency = $this->findCurrency($currencyId); $currency = $this->findCurrency($currencyId);
// set the array with monetary info, if it does not exist. // set the array with monetary info, if it does not exist.
$this->createDefaultDataEntry($journal); $this->createDefaultDataEntry($journal);
@@ -152,12 +152,12 @@ class AccountBalanceGrouped
$this->createDefaultPeriodEntry($journal); $this->createDefaultPeriodEntry($journal);
// is this journal's amount in- our outgoing? // is this journal's amount in- our outgoing?
$key = $this->getDataKey($journal); $key = $this->getDataKey($journal);
$amount = 'spent' === $key ? app('steam')->negative($journal['amount']) : app('steam')->positive($journal['amount']); $amount = 'spent' === $key ? app('steam')->negative($journal['amount']) : app('steam')->positive($journal['amount']);
// get conversion rate // get conversion rate
$rate = $this->getRate($currency, $journal['date']); $rate = $this->getRate($currency, $journal['date']);
$amountConverted = bcmul($amount, $rate); $amountConverted = bcmul($amount, $rate);
// perhaps transaction already has the foreign amount in the native currency. // perhaps transaction already has the foreign amount in the native currency.
if ((int) $journal['foreign_currency_id'] === $this->default->id) { if ((int) $journal['foreign_currency_id'] === $this->default->id) {
@@ -166,7 +166,7 @@ class AccountBalanceGrouped
} }
// add normal entry // add normal entry
$this->data[$currencyId][$period][$key] = bcadd($this->data[$currencyId][$period][$key], $amount); $this->data[$currencyId][$period][$key] = bcadd($this->data[$currencyId][$period][$key], $amount);
// add converted entry // add converted entry
$convertedKey = sprintf('native_%s', $key); $convertedKey = sprintf('native_%s', $key);
@@ -185,7 +185,7 @@ class AccountBalanceGrouped
private function createDefaultDataEntry(array $journal): void private function createDefaultDataEntry(array $journal): void
{ {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$this->data[$currencyId] ??= [ $this->data[$currencyId] ??= [
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
@@ -202,8 +202,8 @@ class AccountBalanceGrouped
private function createDefaultPeriodEntry(array $journal): void private function createDefaultPeriodEntry(array $journal): void
{ {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$period = $journal['date']->format($this->carbonFormat); $period = $journal['date']->format($this->carbonFormat);
$this->data[$currencyId][$period] ??= [ $this->data[$currencyId][$period] ??= [
'period' => $period, 'period' => $period,
'spent' => '0', 'spent' => '0',

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Api; namespace FireflyIII\Support\Http\Api;
use Carbon\Carbon; use Carbon\Carbon;
use DateTimeInterface;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
/** /**
@@ -46,7 +45,7 @@ trait ConvertsExchangeRates
// if not enabled, return the same array but without conversion: // if not enabled, return the same array but without conversion:
return $set; return $set;
$this->enabled = false; $this->enabled = false;
if (false === $this->enabled) { if (false === $this->enabled) {
$set['converted'] = false; $set['converted'] = false;
@@ -56,8 +55,8 @@ trait ConvertsExchangeRates
$set['converted'] = true; $set['converted'] = true;
/** @var TransactionCurrency $native */ /** @var TransactionCurrency $native */
$native = app('amount')->getDefaultCurrency(); $native = app('amount')->getDefaultCurrency();
$currency = $this->getCurrency((int) $set['currency_id']); $currency = $this->getCurrency((int) $set['currency_id']);
if ($native->id === $currency->id) { if ($native->id === $currency->id) {
$set['native_currency_id'] = (string) $currency->id; $set['native_currency_id'] = (string) $currency->id;
$set['native_currency_code'] = $currency->code; $set['native_currency_code'] = $currency->code;
@@ -67,9 +66,9 @@ trait ConvertsExchangeRates
return $set; return $set;
} }
foreach ($set['entries'] as $date => $entry) { foreach ($set['entries'] as $date => $entry) {
$carbon = Carbon::createFromFormat(DateTimeInterface::ATOM, $date); $carbon = Carbon::createFromFormat(\DateTimeInterface::ATOM, $date);
$rate = $this->getRate($currency, $native, $carbon); $rate = $this->getRate($currency, $native, $carbon);
$rate = '0' === $rate ? '1' : $rate; $rate = '0' === $rate ? '1' : $rate;
app('log')->debug(sprintf('bcmul("%s", "%s")', (string) $entry, $rate)); app('log')->debug(sprintf('bcmul("%s", "%s")', (string) $entry, $rate));
$set['entries'][$date] = (float) bcmul((string) $entry, $rate); $set['entries'][$date] = (float) bcmul((string) $entry, $rate);
} }

View File

@@ -85,8 +85,8 @@ class ExchangeRateConverter
*/ */
private function getRate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string private function getRate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string
{ {
$key = $this->getCacheKey($from, $to, $date); $key = $this->getCacheKey($from, $to, $date);
$res = Cache::get($key, null); $res = Cache::get($key, null);
// find in cache // find in cache
if (null !== $res) { if (null !== $res) {
@@ -96,7 +96,7 @@ class ExchangeRateConverter
} }
// find in database // find in database
$rate = $this->getFromDB($from->id, $to->id, $date->format('Y-m-d')); $rate = $this->getFromDB($from->id, $to->id, $date->format('Y-m-d'));
if (null !== $rate) { if (null !== $rate) {
Cache::forever($key, $rate); Cache::forever($key, $rate);
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d'))); Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
@@ -105,7 +105,7 @@ class ExchangeRateConverter
} }
// find reverse in database // find reverse in database
$rate = $this->getFromDB($to->id, $from->id, $date->format('Y-m-d')); $rate = $this->getFromDB($to->id, $from->id, $date->format('Y-m-d'));
if (null !== $rate) { if (null !== $rate) {
$rate = bcdiv('1', $rate); $rate = bcdiv('1', $rate);
Cache::forever($key, $rate); Cache::forever($key, $rate);
@@ -143,7 +143,7 @@ class ExchangeRateConverter
if ($from === $to) { if ($from === $to) {
return '1'; return '1';
} }
$key = sprintf('cer-%d-%d-%s', $from, $to, $date); $key = sprintf('cer-%d-%d-%s', $from, $to, $date);
// perhaps the rate has been cached during this particular run // perhaps the rate has been cached during this particular run
$preparedRate = $this->prepared[$date][$from][$to] ?? null; $preparedRate = $this->prepared[$date][$from][$to] ?? null;
@@ -153,7 +153,7 @@ class ExchangeRateConverter
return $preparedRate; return $preparedRate;
} }
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($key); $cache->addProperty($key);
if ($cache->has()) { if ($cache->has()) {
$rate = $cache->get(); $rate = $cache->get();
@@ -166,15 +166,16 @@ class ExchangeRateConverter
} }
/** @var null|CurrencyExchangeRate $result */ /** @var null|CurrencyExchangeRate $result */
$result = auth()->user() $result = auth()->user()
?->currencyExchangeRates() ?->currencyExchangeRates()
->where('from_currency_id', $from) ->where('from_currency_id', $from)
->where('to_currency_id', $to) ->where('to_currency_id', $to)
->where('date', '<=', $date) ->where('date', '<=', $date)
->orderBy('date', 'DESC') ->orderBy('date', 'DESC')
->first(); ->first()
;
++$this->queryCount; ++$this->queryCount;
$rate = (string) $result?->rate; $rate = (string) $result?->rate;
if ('' === $rate) { if ('' === $rate) {
app('log')->debug(sprintf('ExchangeRateConverter: Found no rate for #%d->#%d (%s) in the DB.', $from, $to, $date)); app('log')->debug(sprintf('ExchangeRateConverter: Found no rate for #%d->#%d (%s) in the DB.', $from, $to, $date));
@@ -214,13 +215,13 @@ class ExchangeRateConverter
if ($euroId === $currency->id) { if ($euroId === $currency->id) {
return '1'; return '1';
} }
$rate = $this->getFromDB($currency->id, $euroId, $date->format('Y-m-d')); $rate = $this->getFromDB($currency->id, $euroId, $date->format('Y-m-d'));
if (null !== $rate) { if (null !== $rate) {
// app('log')->debug(sprintf('Rate for %s to EUR is %s.', $currency->code, $rate)); // app('log')->debug(sprintf('Rate for %s to EUR is %s.', $currency->code, $rate));
return $rate; return $rate;
} }
$rate = $this->getFromDB($euroId, $currency->id, $date->format('Y-m-d')); $rate = $this->getFromDB($euroId, $currency->id, $date->format('Y-m-d'));
if (null !== $rate) { if (null !== $rate) {
return bcdiv('1', $rate); return bcdiv('1', $rate);
// app('log')->debug(sprintf('Inverted rate for %s to EUR is %s.', $currency->code, $rate)); // app('log')->debug(sprintf('Inverted rate for %s to EUR is %s.', $currency->code, $rate));
@@ -249,7 +250,7 @@ class ExchangeRateConverter
if ($cache->has()) { if ($cache->has()) {
return (int) $cache->get(); return (int) $cache->get();
} }
$euro = TransactionCurrency::whereCode('EUR')->first(); $euro = TransactionCurrency::whereCode('EUR')->first();
++$this->queryCount; ++$this->queryCount;
if (null === $euro) { if (null === $euro) {
throw new FireflyException('Cannot find EUR in system, cannot do currency conversion.'); throw new FireflyException('Cannot find EUR in system, cannot do currency conversion.');
@@ -271,13 +272,14 @@ class ExchangeRateConverter
$start->startOfDay(); $start->startOfDay();
$end->endOfDay(); $end->endOfDay();
Log::debug(sprintf('Preparing for %s to %s between %s and %s', $from->code, $to->code, $start->format('Y-m-d'), $end->format('Y-m-d'))); Log::debug(sprintf('Preparing for %s to %s between %s and %s', $from->code, $to->code, $start->format('Y-m-d'), $end->format('Y-m-d')));
$set = auth()->user() $set = auth()->user()
->currencyExchangeRates() ->currencyExchangeRates()
->where('from_currency_id', $from->id) ->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id) ->where('to_currency_id', $to->id)
->where('date', '<=', $end->format('Y-m-d')) ->where('date', '<=', $end->format('Y-m-d'))
->where('date', '>=', $start->format('Y-m-d')) ->where('date', '>=', $start->format('Y-m-d'))
->orderBy('date', 'DESC')->get(); ->orderBy('date', 'DESC')->get()
;
++$this->queryCount; ++$this->queryCount;
if (0 === $set->count()) { if (0 === $set->count()) {
Log::debug('No prepared rates found in this period, use the fallback'); Log::debug('No prepared rates found in this period, use the fallback');
@@ -291,10 +293,10 @@ class ExchangeRateConverter
$this->isPrepared = true; $this->isPrepared = true;
// so there is a fallback just in case. Now loop the set of rates we DO have. // so there is a fallback just in case. Now loop the set of rates we DO have.
$temp = []; $temp = [];
$count = 0; $count = 0;
foreach ($set as $rate) { foreach ($set as $rate) {
$date = $rate->date->format('Y-m-d'); $date = $rate->date->format('Y-m-d');
$temp[$date] ??= [ $temp[$date] ??= [
$from->id => [ $from->id => [
$to->id => $rate->rate, $to->id => $rate->rate,
@@ -303,11 +305,11 @@ class ExchangeRateConverter
++$count; ++$count;
} }
Log::debug(sprintf('Found %d rates in this period.', $count)); Log::debug(sprintf('Found %d rates in this period.', $count));
$currentStart = clone $start; $currentStart = clone $start;
while ($currentStart->lte($end)) { while ($currentStart->lte($end)) {
$currentDate = $currentStart->format('Y-m-d'); $currentDate = $currentStart->format('Y-m-d');
$this->prepared[$currentDate] ??= []; $this->prepared[$currentDate] ??= [];
$fallback = $temp[$currentDate][$from->id][$to->id] ?? $this->fallback[$from->id][$to->id] ?? '0'; $fallback = $temp[$currentDate][$from->id][$to->id] ?? $this->fallback[$from->id][$to->id] ?? '0';
if (0 === count($this->prepared[$currentDate]) && 0 !== bccomp('0', $fallback)) { if (0 === count($this->prepared[$currentDate]) && 0 !== bccomp('0', $fallback)) {
// fill from temp or fallback or from temp (see before) // fill from temp or fallback or from temp (see before)
$this->prepared[$currentDate][$from->id][$to->id] = $fallback; $this->prepared[$currentDate][$from->id][$to->id] = $fallback;

View File

@@ -40,7 +40,7 @@ trait ParsesQueryFilters
private function dateOrToday(QueryParameters $parameters, string $field): Carbon private function dateOrToday(QueryParameters $parameters, string $field): Carbon
{ {
$date = today(); $date = today();
$value = $parameters->filter()?->value($field, date('Y-m-d')); $value = $parameters->filter()?->value($field, date('Y-m-d'));

View File

@@ -30,7 +30,7 @@ use Illuminate\Support\Facades\Log;
class SummaryBalanceGrouped class SummaryBalanceGrouped
{ {
private const string SUM = 'sum'; private const string SUM = 'sum';
private array $amounts = []; private array $amounts = [];
private array $currencies; private array $currencies;
private CurrencyRepositoryInterface $currencyRepository; private CurrencyRepositoryInterface $currencyRepository;
@@ -47,9 +47,9 @@ class SummaryBalanceGrouped
public function groupData(): array public function groupData(): array
{ {
Log::debug('Now going to group data.'); Log::debug('Now going to group data.');
$return = []; $return = [];
foreach ($this->keys as $key) { foreach ($this->keys as $key) {
$title = match ($key) { $title = match ($key) {
'sum' => 'balance', 'sum' => 'balance',
'expense' => 'spent', 'expense' => 'spent',
'income' => 'earned', 'income' => 'earned',
@@ -108,11 +108,11 @@ class SummaryBalanceGrouped
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
// transaction info: // transaction info:
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$amount = bcmul($journal['amount'], $multiplier); $amount = bcmul($journal['amount'], $multiplier);
$currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId); $currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = $currency; $this->currencies[$currencyId] = $currency;
$nativeAmount = $converter->convert($currency, $this->default, $journal['date'], $amount); $nativeAmount = $converter->convert($currency, $this->default, $journal['date'], $amount);
if ((int) $journal['foreign_currency_id'] === $this->default->id) { if ((int) $journal['foreign_currency_id'] === $this->default->id) {
// use foreign amount instead // use foreign amount instead
$nativeAmount = $journal['foreign_amount']; $nativeAmount = $journal['foreign_amount'];

View File

@@ -56,8 +56,8 @@ trait ValidatesUserGroupTrait
} }
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$groupId = 0; $groupId = 0;
if (!$request->has('user_group_id')) { if (!$request->has('user_group_id')) {
$groupId = $user->user_group_id; $groupId = $user->user_group_id;
Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId)); Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
@@ -68,7 +68,7 @@ trait ValidatesUserGroupTrait
} }
/** @var UserGroupRepositoryInterface $repository */ /** @var UserGroupRepositoryInterface $repository */
$repository = app(UserGroupRepositoryInterface::class); $repository = app(UserGroupRepositoryInterface::class);
$repository->setUser($user); $repository->setUser($user);
$memberships = $repository->getMembershipsFromGroupId($groupId); $memberships = $repository->getMembershipsFromGroupId($groupId);
@@ -79,14 +79,14 @@ trait ValidatesUserGroupTrait
} }
// need to get the group from the membership: // need to get the group from the membership:
$group = $repository->getById($groupId); $group = $repository->getById($groupId);
if (null === $group) { if (null === $group) {
Log::debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId)); Log::debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId));
throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group')); throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group'));
} }
Log::debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title)); Log::debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title));
$roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : []; // @phpstan-ignore-line $roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : []; // @phpstan-ignore-line
if (0 === count($roles)) { if (0 === count($roles)) {
Log::debug('validateUserGroup: no roles defined, so no access.'); Log::debug('validateUserGroup: no roles defined, so no access.');

View File

@@ -55,10 +55,10 @@ trait AugumentData
/** @var Account $expenseAccount */ /** @var Account $expenseAccount */
foreach ($accounts as $expenseAccount) { foreach ($accounts as $expenseAccount) {
$collection = new Collection(); $collection = new Collection();
$collection->push($expenseAccount); $collection->push($expenseAccount);
$revenue = $repository->findByName($expenseAccount->name, [AccountType::REVENUE]); $revenue = $repository->findByName($expenseAccount->name, [AccountType::REVENUE]);
if (null !== $revenue) { if (null !== $revenue) {
$collection->push($revenue); $collection->push($revenue);
} }
@@ -115,7 +115,7 @@ trait AugumentData
$return[$accountId] = $grouped[$accountId][0]['name']; $return[$accountId] = $grouped[$accountId][0]['name'];
} }
} }
$return[0] = '(no name)'; $return[0] = '(no name)';
return $return; return $return;
} }
@@ -135,7 +135,7 @@ trait AugumentData
$return[$budgetId] = $grouped[$budgetId][0]['name']; $return[$budgetId] = $grouped[$budgetId][0]['name'];
} }
} }
$return[0] = (string) trans('firefly.no_budget'); $return[0] = (string) trans('firefly.no_budget');
return $return; return $return;
} }
@@ -157,7 +157,7 @@ trait AugumentData
$return[$categoryId] = $grouped[$categoryId][0]['name']; $return[$categoryId] = $grouped[$categoryId][0]['name'];
} }
} }
$return[0] = (string) trans('firefly.no_category'); $return[0] = (string) trans('firefly.no_category');
return $return; return $return;
} }
@@ -168,14 +168,14 @@ trait AugumentData
protected function getLimits(Budget $budget, Carbon $start, Carbon $end): Collection // get data + augment with info protected function getLimits(Budget $budget, Carbon $start, Carbon $end): Collection // get data + augment with info
{ {
/** @var OperationsRepositoryInterface $opsRepository */ /** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class); $opsRepository = app(OperationsRepositoryInterface::class);
/** @var BudgetLimitRepositoryInterface $blRepository */ /** @var BudgetLimitRepositoryInterface $blRepository */
$blRepository = app(BudgetLimitRepositoryInterface::class); $blRepository = app(BudgetLimitRepositoryInterface::class);
$end->endOfMonth(); $end->endOfMonth();
// properties for cache // properties for cache
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($budget->id); $cache->addProperty($budget->id);
@@ -191,7 +191,7 @@ trait AugumentData
/** @var BudgetLimit $entry */ /** @var BudgetLimit $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$currency = $entry->transactionCurrency; $currency = $entry->transactionCurrency;
if (null === $currency) { if (null === $currency) {
$currency = app('amount')->getDefaultCurrency(); $currency = app('amount')->getDefaultCurrency();
@@ -227,7 +227,7 @@ trait AugumentData
/** @var array $journal */ /** @var array $journal */
foreach ($array as $journal) { foreach ($array as $journal) {
$name = '(no name)'; $name = '(no name)';
if (TransactionType::WITHDRAWAL === $journal['transaction_type_type']) { if (TransactionType::WITHDRAWAL === $journal['transaction_type_type']) {
$name = $journal['destination_account_name']; $name = $journal['destination_account_name'];
} }
@@ -250,16 +250,16 @@ trait AugumentData
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$total = $assets->merge($opposing); $total = $assets->merge($opposing);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total); $collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($total);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$sum = [ $sum = [
'grand_sum' => '0', 'grand_sum' => '0',
'per_currency' => [], 'per_currency' => [],
]; ];
// loop to support multi currency // loop to support multi currency
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
// if not set, set to zero: // if not set, set to zero:
if (!array_key_exists($currencyId, $sum['per_currency'])) { if (!array_key_exists($currencyId, $sum['per_currency'])) {

View File

@@ -46,7 +46,7 @@ trait ChartGeneration
protected function accountBalanceChart(Collection $accounts, Carbon $start, Carbon $end): array // chart helper method. protected function accountBalanceChart(Collection $accounts, Carbon $start, Carbon $end): array // chart helper method.
{ {
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('chart.account.account-balance-chart'); $cache->addProperty('chart.account.account-balance-chart');
@@ -56,21 +56,21 @@ trait ChartGeneration
// return $cache->get(); // return $cache->get();
} }
app('log')->debug('Regenerate chart.account.account-balance-chart from scratch.'); app('log')->debug('Regenerate chart.account.account-balance-chart from scratch.');
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
/** @var GeneratorInterface $generator */ /** @var GeneratorInterface $generator */
$generator = app(GeneratorInterface::class); $generator = app(GeneratorInterface::class);
/** @var AccountRepositoryInterface $accountRepos */ /** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class); $accountRepos = app(AccountRepositoryInterface::class);
$default = app('amount')->getDefaultCurrency(); $default = app('amount')->getDefaultCurrency();
$chartData = []; $chartData = [];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
// TODO we can use getAccountCurrency instead. // TODO we can use getAccountCurrency instead.
$currency = $accountRepos->getAccountCurrency($account); $currency = $accountRepos->getAccountCurrency($account);
if (null === $currency) { if (null === $currency) {
$currency = $default; $currency = $default;
} }
@@ -79,7 +79,7 @@ trait ChartGeneration
$currency = $default; $currency = $default;
} }
$currentSet = [ $currentSet = [
'label' => $account->name, 'label' => $account->name,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'entries' => [], 'entries' => [],
@@ -89,16 +89,16 @@ trait ChartGeneration
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end); $range = Steam::finalAccountBalanceInRange($account, $start, clone $end);
$previous = array_values($range)[0]; $previous = array_values($range)[0];
while ($currentStart <= $end) { while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale))); $label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale)));
$balance = $range[$format] ?? $previous; $balance = $range[$format] ?? $previous;
$previous = $balance; $previous = $balance;
$currentStart->addDay(); $currentStart->addDay();
$currentSet['entries'][$label] = $balance['balance']; // TODO or native_balance $currentSet['entries'][$label] = $balance['balance']; // TODO or native_balance
} }
$chartData[] = $currentSet; $chartData[] = $currentSet;
} }
$data = $generator->multiSet($chartData); $data = $generator->multiSet($chartData);
$cache->store($data); $cache->store($data);
return $data; return $data;

View File

@@ -102,7 +102,7 @@ trait CreateStuff
return; return;
} }
$key = RSA::createKey(4096); $key = RSA::createKey(4096);
Log::alert('NO OAuth keys were found. They have been created.'); Log::alert('NO OAuth keys were found. They have been created.');

View File

@@ -90,19 +90,19 @@ trait DateCalculation
protected function getNextPeriods(Carbon $date, string $range): array protected function getNextPeriods(Carbon $date, string $range): array
{ {
// select thing for next 12 periods: // select thing for next 12 periods:
$loop = []; $loop = [];
/** @var Carbon $current */ /** @var Carbon $current */
$current = app('navigation')->startOfPeriod($date, $range); $current = app('navigation')->startOfPeriod($date, $range);
$current = app('navigation')->endOfPeriod($current, $range); $current = app('navigation')->endOfPeriod($current, $range);
$current->addDay(); $current->addDay();
$count = 0; $count = 0;
while ($count < 12) { while ($count < 12) {
$current = app('navigation')->endOfPeriod($current, $range); $current = app('navigation')->endOfPeriod($current, $range);
$currentStart = app('navigation')->startOfPeriod($current, $range); $currentStart = app('navigation')->startOfPeriod($current, $range);
$loop[] = [ $loop[] = [
'label' => $current->format('Y-m-d'), 'label' => $current->format('Y-m-d'),
'title' => app('navigation')->periodShow($current, $range), 'title' => app('navigation')->periodShow($current, $range),
'start' => clone $currentStart, 'start' => clone $currentStart,
@@ -122,7 +122,7 @@ trait DateCalculation
protected function getPreviousPeriods(Carbon $date, string $range): array protected function getPreviousPeriods(Carbon $date, string $range): array
{ {
// select thing for last 12 periods: // select thing for last 12 periods:
$loop = []; $loop = [];
/** @var Carbon $current */ /** @var Carbon $current */
$current = app('navigation')->startOfPeriod($date, $range); $current = app('navigation')->startOfPeriod($date, $range);

View File

@@ -61,13 +61,13 @@ trait GetConfigurationData
$steps = []; $steps = [];
if (is_array($elements) && count($elements) > 0) { if (is_array($elements) && count($elements) > 0) {
foreach ($elements as $key => $options) { foreach ($elements as $key => $options) {
$currentStep = $options; $currentStep = $options;
// get the text: // get the text:
$currentStep['intro'] = (string) trans('intro.' . $route . '_' . $key); $currentStep['intro'] = (string) trans('intro.'.$route.'_'.$key);
// save in array: // save in array:
$steps[] = $currentStep; $steps[] = $currentStep;
} }
} }
app('log')->debug(sprintf('Total basic steps for %s is %d', $routeKey, count($steps))); app('log')->debug(sprintf('Total basic steps for %s is %d', $routeKey, count($steps)));
@@ -82,22 +82,22 @@ trait GetConfigurationData
*/ */
protected function getDateRangeConfig(): array // get configuration + get preferences. protected function getDateRangeConfig(): array // get configuration + get preferences.
{ {
$viewRange = app('navigation')->getViewRange(false); $viewRange = app('navigation')->getViewRange(false);
Log::debug(sprintf('dateRange: the view range is "%s"', $viewRange)); Log::debug(sprintf('dateRange: the view range is "%s"', $viewRange));
/** @var Carbon $start */ /** @var Carbon $start */
$start = session('start'); $start = session('start');
/** @var Carbon $end */ /** @var Carbon $end */
$end = session('end'); $end = session('end');
/** @var Carbon $first */ /** @var Carbon $first */
$first = session('first'); $first = session('first');
$title = sprintf('%s - %s', $start->isoFormat($this->monthAndDayFormat), $end->isoFormat($this->monthAndDayFormat)); $title = sprintf('%s - %s', $start->isoFormat($this->monthAndDayFormat), $end->isoFormat($this->monthAndDayFormat));
$isCustom = true === session('is_custom_range', false); $isCustom = true === session('is_custom_range', false);
$today = today(config('app.timezone')); $today = today(config('app.timezone'));
$ranges = [ $ranges = [
// first range is the current range: // first range is the current range:
$title => [$start, $end], $title => [$start, $end],
]; ];
@@ -127,10 +127,10 @@ trait GetConfigurationData
// today: // today:
/** @var Carbon $todayStart */ /** @var Carbon $todayStart */
$todayStart = app('navigation')->startOfPeriod($today, $viewRange); $todayStart = app('navigation')->startOfPeriod($today, $viewRange);
/** @var Carbon $todayEnd */ /** @var Carbon $todayEnd */
$todayEnd = app('navigation')->endOfPeriod($todayStart, $viewRange); $todayEnd = app('navigation')->endOfPeriod($todayStart, $viewRange);
if ($todayStart->ne($start) || $todayEnd->ne($end)) { if ($todayStart->ne($start) || $todayEnd->ne($end)) {
$ranges[ucfirst((string) trans('firefly.today'))] = [$todayStart, $todayEnd]; $ranges[ucfirst((string) trans('firefly.today'))] = [$todayStart, $todayEnd];
@@ -186,16 +186,16 @@ trait GetConfigurationData
// user is on page with specific instructions: // user is on page with specific instructions:
if ('' !== $specificPage) { if ('' !== $specificPage) {
$routeKey = str_replace('.', '_', $route); $routeKey = str_replace('.', '_', $route);
$elements = config(sprintf('intro.%s', $routeKey . '_' . $specificPage)); $elements = config(sprintf('intro.%s', $routeKey.'_'.$specificPage));
if (is_array($elements) && count($elements) > 0) { if (is_array($elements) && count($elements) > 0) {
foreach ($elements as $key => $options) { foreach ($elements as $key => $options) {
$currentStep = $options; $currentStep = $options;
// get the text: // get the text:
$currentStep['intro'] = (string) trans('intro.' . $route . '_' . $specificPage . '_' . $key); $currentStep['intro'] = (string) trans('intro.'.$route.'_'.$specificPage.'_'.$key);
// save in array: // save in array:
$steps[] = $currentStep; $steps[] = $currentStep;
} }
} }
} }

View File

@@ -32,7 +32,6 @@ use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Throwable;
/** /**
* Trait ModelInformation * Trait ModelInformation
@@ -56,7 +55,7 @@ trait ModelInformation
'count' => 1, 'count' => 1,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage())); app('log')->error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());
$result = 'Could not render view. See log files.'; $result = 'Could not render view. See log files.';
@@ -75,14 +74,14 @@ trait ModelInformation
protected function getLiabilityTypes(): array protected function getLiabilityTypes(): array
{ {
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
// types of liability: // types of liability:
/** @var AccountType $debt */ /** @var AccountType $debt */
$debt = $repository->getAccountTypeByType(AccountType::DEBT); $debt = $repository->getAccountTypeByType(AccountType::DEBT);
/** @var AccountType $loan */ /** @var AccountType $loan */
$loan = $repository->getAccountTypeByType(AccountType::LOAN); $loan = $repository->getAccountTypeByType(AccountType::LOAN);
/** @var AccountType $mortgage */ /** @var AccountType $mortgage */
$mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE); $mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE);
@@ -114,8 +113,8 @@ trait ModelInformation
protected function getTriggersForBill(Bill $bill): array // get info and argument protected function getTriggersForBill(Bill $bill): array // get info and argument
{ {
// TODO duplicate code // TODO duplicate code
$operators = config('search.operators'); $operators = config('search.operators');
$triggers = []; $triggers = [];
foreach ($operators as $key => $operator) { foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) { if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
@@ -143,7 +142,7 @@ trait ModelInformation
'triggers' => $triggers, 'triggers' => $triggers,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage())); app('log')->debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
app('log')->debug($e->getTraceAsString()); app('log')->debug($e->getTraceAsString());
@@ -165,8 +164,8 @@ trait ModelInformation
private function getTriggersForJournal(TransactionJournal $journal): array private function getTriggersForJournal(TransactionJournal $journal): array
{ {
// TODO duplicated code. // TODO duplicated code.
$operators = config('search.operators'); $operators = config('search.operators');
$triggers = []; $triggers = [];
foreach ($operators as $key => $operator) { foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) { if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
@@ -174,18 +173,18 @@ trait ModelInformation
} }
asort($triggers); asort($triggers);
$result = []; $result = [];
$journalTriggers = []; $journalTriggers = [];
$values = []; $values = [];
$index = 0; $index = 0;
// amount, description, category, budget, tags, source, destination, notes, currency type // amount, description, category, budget, tags, source, destination, notes, currency type
// ,type // ,type
/** @var null|Transaction $source */ /** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first(); $source = $journal->transactions()->where('amount', '<', 0)->first();
/** @var null|Transaction $destination */ /** @var null|Transaction $destination */
$destination = $journal->transactions()->where('amount', '>', 0)->first(); $destination = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $destination || null === $source) { if (null === $destination || null === $source) {
return $result; return $result;
} }
@@ -220,21 +219,21 @@ trait ModelInformation
++$index; ++$index;
// category (if) // category (if)
$category = $journal->categories()->first(); $category = $journal->categories()->first();
if (null !== $category) { if (null !== $category) {
$journalTriggers[$index] = 'category_is'; $journalTriggers[$index] = 'category_is';
$values[$index] = $category->name; $values[$index] = $category->name;
++$index; ++$index;
} }
// budget (if) // budget (if)
$budget = $journal->budgets()->first(); $budget = $journal->budgets()->first();
if (null !== $budget) { if (null !== $budget) {
$journalTriggers[$index] = 'budget_is'; $journalTriggers[$index] = 'budget_is';
$values[$index] = $budget->name; $values[$index] = $budget->name;
++$index; ++$index;
} }
// tags (if) // tags (if)
$tags = $journal->tags()->get(); $tags = $journal->tags()->get();
/** @var Tag $tag */ /** @var Tag $tag */
foreach ($tags as $tag) { foreach ($tags as $tag) {
@@ -243,7 +242,7 @@ trait ModelInformation
++$index; ++$index;
} }
// notes (if) // notes (if)
$notes = $journal->notes()->first(); $notes = $journal->notes()->first();
if (null !== $notes) { if (null !== $notes) {
$journalTriggers[$index] = 'notes_are'; $journalTriggers[$index] = 'notes_are';
$values[$index] = $notes->text; $values[$index] = $notes->text;
@@ -259,7 +258,7 @@ trait ModelInformation
'triggers' => $triggers, 'triggers' => $triggers,
]; ];
$string = view('rules.partials.trigger', $renderInfo)->render(); $string = view('rules.partials.trigger', $renderInfo)->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Throwable was thrown in getTriggersForJournal(): %s', $e->getMessage())); app('log')->debug(sprintf('Throwable was thrown in getTriggersForJournal(): %s', $e->getMessage()));
app('log')->debug($e->getTraceAsString()); app('log')->debug($e->getTraceAsString());

View File

@@ -75,11 +75,11 @@ trait PeriodOverview
*/ */
protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for cache // properties for cache
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('account-show-period-entries'); $cache->addProperty('account-show-period-entries');
@@ -89,32 +89,32 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account])); $collector->setAccounts(new Collection([$account]));
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::DEPOSIT]); $collector->setTypes([TransactionType::DEPOSIT]);
$earnedSet = $collector->getExtractedJournals(); $earnedSet = $collector->getExtractedJournals();
// collect all income in this period: // collect all income in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account])); $collector->setAccounts(new Collection([$account]));
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL]); $collector->setTypes([TransactionType::WITHDRAWAL]);
$spentSet = $collector->getExtractedJournals(); $spentSet = $collector->getExtractedJournals();
// collect all transfers in this period: // collect all transfers in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account])); $collector->setAccounts(new Collection([$account]));
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::TRANSFER]); $collector->setTypes([TransactionType::TRANSFER]);
$transferSet = $collector->getExtractedJournals(); $transferSet = $collector->getExtractedJournals();
// loop dates // loop dates
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
@@ -125,15 +125,15 @@ trait PeriodOverview
$transferredIn = $this->filterTransferredIn($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); $transferredIn = $this->filterTransferredIn($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']));
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), 'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn), 'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn),
'spent' => $this->groupByCurrency($spent), 'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned), 'earned' => $this->groupByCurrency($earned),
'transferred_away' => $this->groupByCurrency($transferredAway), 'transferred_away' => $this->groupByCurrency($transferredAway),
'transferred_in' => $this->groupByCurrency($transferredIn), 'transferred_in' => $this->groupByCurrency($transferredIn),
]; ];
} }
$cache->store($entries); $cache->store($entries);
@@ -197,8 +197,8 @@ trait PeriodOverview
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = $journal['foreign_currency_id']; $foreignCurrencyId = $journal['foreign_currency_id'];
if (!array_key_exists($currencyId, $return)) { if (!array_key_exists($currencyId, $return)) {
$return[$currencyId] = [ $return[$currencyId] = [
'amount' => '0', 'amount' => '0',
@@ -240,11 +240,11 @@ trait PeriodOverview
*/ */
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for entries with their amounts. // properties for entries with their amounts.
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($range); $cache->addProperty($range);
@@ -256,32 +256,32 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setCategory($category); $collector->setCategory($category);
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::DEPOSIT]); $collector->setTypes([TransactionType::DEPOSIT]);
$earnedSet = $collector->getExtractedJournals(); $earnedSet = $collector->getExtractedJournals();
// collect all income in this period: // collect all income in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setCategory($category); $collector->setCategory($category);
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL]); $collector->setTypes([TransactionType::WITHDRAWAL]);
$spentSet = $collector->getExtractedJournals(); $spentSet = $collector->getExtractedJournals();
// collect all transfers in this period: // collect all transfers in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setCategory($category); $collector->setCategory($category);
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::TRANSFER]); $collector->setTypes([TransactionType::TRANSFER]);
$transferSet = $collector->getExtractedJournals(); $transferSet = $collector->getExtractedJournals();
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
@@ -289,17 +289,17 @@ trait PeriodOverview
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'transactions' => 0, 'transactions' => 0,
'title' => $title, 'title' => $title,
'route' => route( 'route' => route(
'categories.show', 'categories.show',
[$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
), ),
'total_transactions' => count($spent) + count($earned) + count($transferred), 'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent), 'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned), 'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred), 'transferred' => $this->groupByCurrency($transferred),
]; ];
} }
$cache->store($entries); $cache->store($entries);
@@ -315,11 +315,11 @@ trait PeriodOverview
*/ */
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('no-budget-period-entries'); $cache->addProperty('no-budget-period-entries');
@@ -329,28 +329,28 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// get all expenses without a budget. // get all expenses without a budget.
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->withoutBudget()->withAccountInformation()->setTypes([TransactionType::WITHDRAWAL]); $collector->setRange($start, $end)->withoutBudget()->withAccountInformation()->setTypes([TransactionType::WITHDRAWAL]);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']); $set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($set), 'total_transactions' => count($set),
'spent' => $this->groupByCurrency($set), 'spent' => $this->groupByCurrency($set),
'earned' => [], 'earned' => [],
'transferred_away' => [], 'transferred_away' => [],
'transferred_in' => [], 'transferred_in' => [],
]; ];
} }
$cache->store($entries); $cache->store($entries);
@@ -367,38 +367,38 @@ trait PeriodOverview
protected function getNoCategoryPeriodOverview(Carbon $theDate): array protected function getNoCategoryPeriodOverview(Carbon $theDate): array
{ {
app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d'))); app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
$first = $this->journalRepos->firstNull(); $first = $this->journalRepos->firstNull();
$start = null === $first ? new Carbon() : $first->date; $start = null === $first ? new Carbon() : $first->date;
$end = clone $theDate; $end = clone $theDate;
$end = app('navigation')->endOfPeriod($end, $range); $end = app('navigation')->endOfPeriod($end, $range);
app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d'))); app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d'))); app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
// properties for cache // properties for cache
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->withoutCategory(); $collector->withoutCategory();
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::DEPOSIT]); $collector->setTypes([TransactionType::DEPOSIT]);
$earnedSet = $collector->getExtractedJournals(); $earnedSet = $collector->getExtractedJournals();
// collect all income in this period: // collect all income in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->withoutCategory(); $collector->withoutCategory();
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL]); $collector->setTypes([TransactionType::WITHDRAWAL]);
$spentSet = $collector->getExtractedJournals(); $spentSet = $collector->getExtractedJournals();
// collect all transfers in this period: // collect all transfers in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->withoutCategory(); $collector->withoutCategory();
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::TRANSFER]); $collector->setTypes([TransactionType::TRANSFER]);
@@ -412,13 +412,13 @@ trait PeriodOverview
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), 'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred), 'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent), 'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned), 'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred), 'transferred' => $this->groupByCurrency($transferred),
]; ];
} }
app('log')->debug('End of loops'); app('log')->debug('End of loops');
@@ -432,11 +432,11 @@ trait PeriodOverview
*/ */
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags. protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
{ {
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for cache // properties for cache
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('tag-period-entries'); $cache->addProperty('tag-period-entries');
@@ -446,37 +446,37 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTag($tag); $collector->setTag($tag);
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::DEPOSIT]); $collector->setTypes([TransactionType::DEPOSIT]);
$earnedSet = $collector->getExtractedJournals(); $earnedSet = $collector->getExtractedJournals();
// collect all income in this period: // collect all income in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTag($tag); $collector->setTag($tag);
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::WITHDRAWAL]); $collector->setTypes([TransactionType::WITHDRAWAL]);
$spentSet = $collector->getExtractedJournals(); $spentSet = $collector->getExtractedJournals();
// collect all transfers in this period: // collect all transfers in this period:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTag($tag); $collector->setTag($tag);
$collector->setRange($start, $end); $collector->setRange($start, $end);
$collector->setTypes([TransactionType::TRANSFER]); $collector->setTypes([TransactionType::TRANSFER]);
$transferSet = $collector->getExtractedJournals(); $transferSet = $collector->getExtractedJournals();
// filer all of them: // filer all of them:
$earnedSet = $this->filterJournalsByTag($earnedSet, $tag); $earnedSet = $this->filterJournalsByTag($earnedSet, $tag);
$spentSet = $this->filterJournalsByTag($spentSet, $tag); $spentSet = $this->filterJournalsByTag($spentSet, $tag);
$transferSet = $this->filterJournalsByTag($transferSet, $tag); $transferSet = $this->filterJournalsByTag($transferSet, $tag);
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
@@ -485,17 +485,17 @@ trait PeriodOverview
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'transactions' => 0, 'transactions' => 0,
'title' => $title, 'title' => $title,
'route' => route( 'route' => route(
'tags.show', 'tags.show',
[$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] [$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
), ),
'total_transactions' => count($spent) + count($earned) + count($transferred), 'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent), 'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned), 'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred), 'transferred' => $this->groupByCurrency($transferred),
]; ];
} }
return $entries; return $entries;
@@ -505,7 +505,7 @@ trait PeriodOverview
{ {
$return = []; $return = [];
foreach ($set as $entry) { foreach ($set as $entry) {
$found = false; $found = false;
/** @var array $localTag */ /** @var array $localTag */
foreach ($entry['tags'] as $localTag) { foreach ($entry['tags'] as $localTag) {
@@ -527,12 +527,12 @@ trait PeriodOverview
*/ */
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType)); $types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for cache // properties for cache
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('transactions-period-entries'); $cache->addProperty('transactions-period-entries');
@@ -542,13 +542,13 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all journals in this period (regardless of type) // collect all journals in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes($types)->setRange($start, $end); $collector->setTypes($types)->setRange($start, $end);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$spent = []; $spent = [];
@@ -567,14 +567,14 @@ trait PeriodOverview
$transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
} }
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), 'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred), 'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent), 'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned), 'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred), 'transferred' => $this->groupByCurrency($transferred),
]; ];
} }
return $entries; return $entries;

View File

@@ -37,7 +37,6 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Search\OperatorQuerySearch; use FireflyIII\Support\Search\OperatorQuerySearch;
use Throwable;
/** /**
* Trait RenderPartialViews * Trait RenderPartialViews
@@ -52,24 +51,24 @@ trait RenderPartialViews
protected function budgetEntry(array $attributes): string // generate view for report. protected function budgetEntry(array $attributes): string // generate view for report.
{ {
/** @var PopupReportInterface $popupHelper */ /** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class); $popupHelper = app(PopupReportInterface::class);
/** @var BudgetRepositoryInterface $budgetRepository */ /** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class); $budgetRepository = app(BudgetRepositoryInterface::class);
$budget = $budgetRepository->find((int) $attributes['budgetId']); $budget = $budgetRepository->find((int) $attributes['budgetId']);
$accountRepos = app(AccountRepositoryInterface::class); $accountRepos = app(AccountRepositoryInterface::class);
$account = $accountRepos->find((int) $attributes['accountId']); $account = $accountRepos->find((int) $attributes['accountId']);
if (null === $budget || null === $account) { if (null === $budget || null === $account) {
throw new FireflyException('Could not render popup.report.balance-amount because budget or account is null.'); throw new FireflyException('Could not render popup.report.balance-amount because budget or account is null.');
} }
$journals = $popupHelper->balanceForBudget($budget, $account, $attributes); $journals = $popupHelper->balanceForBudget($budget, $account, $attributes);
try { try {
$view = view('popup.report.balance-amount', compact('journals', 'budget', 'account'))->render(); $view = view('popup.report.balance-amount', compact('journals', 'budget', 'account'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Could not render: %s', $e->getMessage())); app('log')->error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.'; $view = 'Firefly III could not render the view. Please see the log files.';
@@ -92,7 +91,7 @@ trait RenderPartialViews
try { try {
$result = view('reports.options.budget', compact('budgets'))->render(); $result = view('reports.options.budget', compact('budgets'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage())); app('log')->error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage()));
$result = 'Could not render view.'; $result = 'Could not render view.';
@@ -113,18 +112,18 @@ trait RenderPartialViews
$budgetRepository = app(BudgetRepositoryInterface::class); $budgetRepository = app(BudgetRepositoryInterface::class);
/** @var PopupReportInterface $popupHelper */ /** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class); $popupHelper = app(PopupReportInterface::class);
$budget = $budgetRepository->find((int) $attributes['budgetId']); $budget = $budgetRepository->find((int) $attributes['budgetId']);
if (null === $budget) { if (null === $budget) {
// transactions without a budget. // transactions without a budget.
$budget = new Budget(); $budget = new Budget();
} }
$journals = $popupHelper->byBudget($budget, $attributes); $journals = $popupHelper->byBudget($budget, $attributes);
try { try {
$view = view('popup.report.budget-spent-amount', compact('journals', 'budget'))->render(); $view = view('popup.report.budget-spent-amount', compact('journals', 'budget'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Could not render: %s', $e->getMessage())); app('log')->error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.'; $view = 'Firefly III could not render the view. Please see the log files.';
@@ -142,7 +141,7 @@ trait RenderPartialViews
protected function categoryEntry(array $attributes): string // generate view for report. protected function categoryEntry(array $attributes): string // generate view for report.
{ {
/** @var PopupReportInterface $popupHelper */ /** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class); $popupHelper = app(PopupReportInterface::class);
/** @var CategoryRepositoryInterface $categoryRepository */ /** @var CategoryRepositoryInterface $categoryRepository */
$categoryRepository = app(CategoryRepositoryInterface::class); $categoryRepository = app(CategoryRepositoryInterface::class);
@@ -151,7 +150,7 @@ trait RenderPartialViews
try { try {
$view = view('popup.report.category-entry', compact('journals', 'category'))->render(); $view = view('popup.report.category-entry', compact('journals', 'category'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Could not render: %s', $e->getMessage())); app('log')->error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.'; $view = 'Firefly III could not render the view. Please see the log files.';
@@ -174,7 +173,7 @@ trait RenderPartialViews
try { try {
$result = view('reports.options.category', compact('categories'))->render(); $result = view('reports.options.category', compact('categories'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Cannot render reports.options.category: %s', $e->getMessage())); app('log')->error(sprintf('Cannot render reports.options.category: %s', $e->getMessage()));
$result = 'Could not render view.'; $result = 'Could not render view.';
@@ -216,7 +215,7 @@ trait RenderPartialViews
try { try {
$result = view('reports.options.double', compact('set'))->render(); $result = view('reports.options.double', compact('set'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage())); app('log')->error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage()));
$result = 'Could not render view.'; $result = 'Could not render view.';
@@ -237,19 +236,19 @@ trait RenderPartialViews
$accountRepository = app(AccountRepositoryInterface::class); $accountRepository = app(AccountRepositoryInterface::class);
/** @var PopupReportInterface $popupHelper */ /** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class); $popupHelper = app(PopupReportInterface::class);
$account = $accountRepository->find((int) $attributes['accountId']); $account = $accountRepository->find((int) $attributes['accountId']);
if (null === $account) { if (null === $account) {
return 'This is an unknown account. Apologies.'; return 'This is an unknown account. Apologies.';
} }
$journals = $popupHelper->byExpenses($account, $attributes); $journals = $popupHelper->byExpenses($account, $attributes);
try { try {
$view = view('popup.report.expense-entry', compact('journals', 'account'))->render(); $view = view('popup.report.expense-entry', compact('journals', 'account'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Could not render: %s', $e->getMessage())); app('log')->error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.'; $view = 'Firefly III could not render the view. Please see the log files.';
@@ -266,8 +265,8 @@ trait RenderPartialViews
*/ */
protected function getCurrentActions(Rule $rule): array // get info from object and present. protected function getCurrentActions(Rule $rule): array // get info from object and present.
{ {
$index = 0; $index = 0;
$actions = []; $actions = [];
// must be repos // must be repos
$currentActions = $rule->ruleActions()->orderBy('order', 'ASC')->get(); $currentActions = $rule->ruleActions()->orderBy('order', 'ASC')->get();
@@ -285,7 +284,7 @@ trait RenderPartialViews
'count' => $count, 'count' => $count,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage())); app('log')->debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());
@@ -306,8 +305,8 @@ trait RenderPartialViews
protected function getCurrentTriggers(Rule $rule): array // get info from object and present. protected function getCurrentTriggers(Rule $rule): array // get info from object and present.
{ {
// TODO duplicated code. // TODO duplicated code.
$operators = config('search.operators'); $operators = config('search.operators');
$triggers = []; $triggers = [];
foreach ($operators as $key => $operator) { foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) { if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
@@ -325,7 +324,7 @@ trait RenderPartialViews
$count = ($index + 1); $count = ($index + 1);
try { try {
$rootOperator = OperatorQuerySearch::getRootOperator((string) $entry->trigger_type); $rootOperator = OperatorQuerySearch::getRootOperator((string) $entry->trigger_type);
if (str_starts_with($rootOperator, '-')) { if (str_starts_with($rootOperator, '-')) {
$rootOperator = substr($rootOperator, 1); $rootOperator = substr($rootOperator, 1);
} }
@@ -340,7 +339,7 @@ trait RenderPartialViews
'triggers' => $triggers, 'triggers' => $triggers,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage())); app('log')->debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());
@@ -365,18 +364,18 @@ trait RenderPartialViews
$accountRepository = app(AccountRepositoryInterface::class); $accountRepository = app(AccountRepositoryInterface::class);
/** @var PopupReportInterface $popupHelper */ /** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class); $popupHelper = app(PopupReportInterface::class);
$account = $accountRepository->find((int) $attributes['accountId']); $account = $accountRepository->find((int) $attributes['accountId']);
if (null === $account) { if (null === $account) {
return 'This is an unknown category. Apologies.'; return 'This is an unknown category. Apologies.';
} }
$journals = $popupHelper->byIncome($account, $attributes); $journals = $popupHelper->byIncome($account, $attributes);
try { try {
$view = view('popup.report.income-entry', compact('journals', 'account'))->render(); $view = view('popup.report.income-entry', compact('journals', 'account'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Could not render: %s', $e->getMessage())); app('log')->error(sprintf('Could not render: %s', $e->getMessage()));
$view = 'Firefly III could not render the view. Please see the log files.'; $view = 'Firefly III could not render the view. Please see the log files.';
@@ -395,7 +394,7 @@ trait RenderPartialViews
{ {
try { try {
$result = view('reports.options.no-options')->render(); $result = view('reports.options.no-options')->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Cannot render reports.options.no-options: %s', $e->getMessage())); app('log')->error(sprintf('Cannot render reports.options.no-options: %s', $e->getMessage()));
$result = 'Could not render view.'; $result = 'Could not render view.';
@@ -418,7 +417,7 @@ trait RenderPartialViews
try { try {
$result = view('reports.options.tag', compact('tags'))->render(); $result = view('reports.options.tag', compact('tags'))->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage())); app('log')->error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage()));
$result = 'Could not render view.'; $result = 'Could not render view.';

View File

@@ -30,7 +30,6 @@ use FireflyIII\Http\Requests\RuleFormRequest;
use FireflyIII\Http\Requests\TestRuleFormRequest; use FireflyIII\Http\Requests\TestRuleFormRequest;
use FireflyIII\Support\Binder\AccountList; use FireflyIII\Support\Binder\AccountList;
use FireflyIII\User; use FireflyIII\User;
use Hash;
use Illuminate\Contracts\Validation\Validator as ValidatorContract; use Illuminate\Contracts\Validation\Validator as ValidatorContract;
use Illuminate\Routing\Route; use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
@@ -83,13 +82,13 @@ trait RequestInformation
$page = $this->getPageName(); $page = $this->getPageName();
$specificPage = $this->getSpecificPageName(); $specificPage = $this->getSpecificPageName();
// indicator if user has seen the help for this page ( + special page): // indicator if user has seen the help for this page ( + special page):
$key = sprintf('shown_demo_%s%s', $page, $specificPage); $key = sprintf('shown_demo_%s%s', $page, $specificPage);
// is there an intro for this route? // is there an intro for this route?
$intro = config(sprintf('intro.%s', $page)) ?? []; $intro = config(sprintf('intro.%s', $page)) ?? [];
$specialIntro = config(sprintf('intro.%s%s', $page, $specificPage)) ?? []; $specialIntro = config(sprintf('intro.%s%s', $page, $specificPage)) ?? [];
// some routes have a "what" parameter, which indicates a special page: // some routes have a "what" parameter, which indicates a special page:
$shownDemo = true; $shownDemo = true;
// both must be array and either must be > 0 // both must be array and either must be > 0
if (count($intro) > 0 || count($specialIntro) > 0) { if (count($intro) > 0 || count($specialIntro) > 0) {
$shownDemo = app('preferences')->get($key, false)->data; $shownDemo = app('preferences')->get($key, false)->data;
@@ -123,7 +122,7 @@ trait RequestInformation
final protected function notInSessionRange(Carbon $date): bool // Validate a preference final protected function notInSessionRange(Carbon $date): bool // Validate a preference
{ {
/** @var Carbon $start */ /** @var Carbon $start */
$start = session('start', today(config('app.timezone'))->startOfMonth()); $start = session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */ /** @var Carbon $end */
$end = session('end', today(config('app.timezone'))->endOfMonth()); $end = session('end', today(config('app.timezone'))->endOfMonth());
@@ -145,20 +144,20 @@ trait RequestInformation
final protected function parseAttributes(array $attributes): array // parse input + return result final protected function parseAttributes(array $attributes): array // parse input + return result
{ {
$attributes['location'] ??= ''; $attributes['location'] ??= '';
$attributes['accounts'] = AccountList::routeBinder($attributes['accounts'] ?? '', new Route('get', '', [])); $attributes['accounts'] = AccountList::routeBinder($attributes['accounts'] ?? '', new Route('get', '', []));
$date = Carbon::createFromFormat('Ymd', $attributes['startDate']); $date = Carbon::createFromFormat('Ymd', $attributes['startDate']);
if (null === $date) { if (null === $date) {
$date = today(config('app.timezone')); $date = today(config('app.timezone'));
} }
$date->startOfMonth(); $date->startOfMonth();
$attributes['startDate'] = $date; $attributes['startDate'] = $date;
$date2 = Carbon::createFromFormat('Ymd', $attributes['endDate']); $date2 = Carbon::createFromFormat('Ymd', $attributes['endDate']);
if (null === $date2) { if (null === $date2) {
$date2 = today(config('app.timezone')); $date2 = today(config('app.timezone'));
} }
$date2->endOfDay(); $date2->endOfDay();
$attributes['endDate'] = $date2; $attributes['endDate'] = $date2;
return $attributes; return $attributes;
} }
@@ -170,7 +169,7 @@ trait RequestInformation
*/ */
final protected function validatePassword(User $user, string $current, string $new): bool // get request info final protected function validatePassword(User $user, string $current, string $new): bool // get request info
{ {
if (!Hash::check($current, $user->password)) { if (!\Hash::check($current, $user->password)) {
throw new ValidationException((string) trans('firefly.invalid_current_password')); throw new ValidationException((string) trans('firefly.invalid_current_password'));
} }

View File

@@ -28,7 +28,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Support\Search\OperatorQuerySearch; use FireflyIII\Support\Search\OperatorQuerySearch;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Throwable;
/** /**
* Trait RuleManagement * Trait RuleManagement
@@ -55,7 +54,7 @@ trait RuleManagement
'count' => $index + 1, 'count' => $index + 1,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->error(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage())); app('log')->error(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());
@@ -74,8 +73,8 @@ trait RuleManagement
protected function getPreviousTriggers(Request $request): array protected function getPreviousTriggers(Request $request): array
{ {
// TODO duplicated code. // TODO duplicated code.
$operators = config('search.operators'); $operators = config('search.operators');
$triggers = []; $triggers = [];
foreach ($operators as $key => $operator) { foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) { if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key)); $triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
@@ -100,7 +99,7 @@ trait RuleManagement
'triggers' => $triggers, 'triggers' => $triggers,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); app('log')->debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());
@@ -129,7 +128,7 @@ trait RuleManagement
} }
asort($triggers); asort($triggers);
$index = 0; $index = 0;
foreach ($submittedOperators as $operator) { foreach ($submittedOperators as $operator) {
$rootOperator = OperatorQuerySearch::getRootOperator($operator['type']); $rootOperator = OperatorQuerySearch::getRootOperator($operator['type']);
$needsContext = (bool) config(sprintf('search.operators.%s.needs_context', $rootOperator)); $needsContext = (bool) config(sprintf('search.operators.%s.needs_context', $rootOperator));
@@ -146,7 +145,7 @@ trait RuleManagement
'triggers' => $triggers, 'triggers' => $triggers,
] ]
)->render(); )->render();
} catch (Throwable $e) { } catch (\Throwable $e) {
app('log')->debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); app('log')->debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());

View File

@@ -39,14 +39,15 @@ trait TransactionCalculation
*/ */
protected function getExpensesForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array protected function getExpensesForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array
{ {
$total = $accounts->merge($opposing); $total = $accounts->merge($opposing);
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($total) $collector->setAccounts($total)
->setRange($start, $end) ->setRange($start, $end)
->withAccountInformation() ->withAccountInformation()
->setTypes([TransactionType::WITHDRAWAL]); ->setTypes([TransactionType::WITHDRAWAL])
;
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }
@@ -60,7 +61,8 @@ trait TransactionCalculation
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]) $collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setTags($tags)->withAccountInformation(); ->setTags($tags)->withAccountInformation()
;
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }
@@ -73,7 +75,8 @@ trait TransactionCalculation
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]) $collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setBudgets($budgets)->withAccountInformation(); ->setBudgets($budgets)->withAccountInformation()
;
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }
@@ -90,7 +93,8 @@ trait TransactionCalculation
->setRange($start, $end) ->setRange($start, $end)
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]) ->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setCategories($categories) ->setCategories($categories)
->withAccountInformation(); ->withAccountInformation()
;
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }
@@ -103,7 +107,8 @@ trait TransactionCalculation
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]) $collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setCategories($categories)->withAccountInformation(); ->setCategories($categories)->withAccountInformation()
;
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }
@@ -113,7 +118,7 @@ trait TransactionCalculation
*/ */
protected function getIncomeForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array protected function getIncomeForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array
{ {
$total = $accounts->merge($opposing); $total = $accounts->merge($opposing);
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
@@ -130,7 +135,8 @@ trait TransactionCalculation
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]) $collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setTags($tags)->withAccountInformation(); ->setTags($tags)->withAccountInformation()
;
return $collector->getExtractedJournals(); return $collector->getExtractedJournals();
} }

View File

@@ -69,7 +69,7 @@ trait UserNavigation
final protected function isEditableGroup(TransactionGroup $group): bool final protected function isEditableGroup(TransactionGroup $group): bool
{ {
/** @var null|TransactionJournal $journal */ /** @var null|TransactionJournal $journal */
$journal = $group->transactionJournals()->first(); $journal = $group->transactionJournals()->first();
if (null === $journal) { if (null === $journal) {
return false; return false;
} }
@@ -96,10 +96,10 @@ trait UserNavigation
return redirect(route('index')); return redirect(route('index'));
} }
$journal = $transaction->transactionJournal; $journal = $transaction->transactionJournal;
/** @var null|Transaction $other */ /** @var null|Transaction $other */
$other = $journal->transactions()->where('id', '!=', $transaction->id)->first(); $other = $journal->transactions()->where('id', '!=', $transaction->id)->first();
if (null === $other) { if (null === $other) {
app('log')->error(sprintf('Account #%d has no valid journals. Dont know where it belongs.', $account->id)); app('log')->error(sprintf('Account #%d has no valid journals. Dont know where it belongs.', $account->id));
session()->flash('error', trans('firefly.cant_find_redirect_account')); session()->flash('error', trans('firefly.cant_find_redirect_account'));
@@ -119,7 +119,7 @@ trait UserNavigation
final protected function redirectGroupToAccount(TransactionGroup $group) final protected function redirectGroupToAccount(TransactionGroup $group)
{ {
/** @var null|TransactionJournal $journal */ /** @var null|TransactionJournal $journal */
$journal = $group->transactionJournals()->first(); $journal = $group->transactionJournals()->first();
if (null === $journal) { if (null === $journal) {
app('log')->error(sprintf('No journals in group #%d', $group->id)); app('log')->error(sprintf('No journals in group #%d', $group->id));

View File

@@ -37,7 +37,7 @@ trait UserGroupDetectable
public function detectUserGroup(): ?UserGroup public function detectUserGroup(): ?UserGroup
{ {
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
app('log')->debug('Now in detectUserGroup()'); app('log')->debug('Now in detectUserGroup()');
/** @var null|UserGroup $userGroup */ /** @var null|UserGroup $userGroup */
@@ -49,7 +49,7 @@ trait UserGroupDetectable
app('log')->debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id)); app('log')->debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id));
$userGroupId = (int) $user->user_group_id; $userGroupId = (int) $user->user_group_id;
} }
$userGroup = UserGroup::find($userGroupId); $userGroup = UserGroup::find($userGroupId);
if (null === $userGroup) { if (null === $userGroup) {
app('log')->error(sprintf('Request class has user_group_id (#%d), but group does not exist.', $userGroupId)); app('log')->error(sprintf('Request class has user_group_id (#%d), but group does not exist.', $userGroupId));

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
use Carbon\Carbon; use Carbon\Carbon;
use DB;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\ObjectGroup;
@@ -37,8 +36,6 @@ use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Override;
use stdClass;
/** /**
* Class AccountEnrichment * Class AccountEnrichment
@@ -66,7 +63,7 @@ class AccountEnrichment implements EnrichmentInterface
$this->end = null; $this->end = null;
} }
#[Override] #[\Override]
public function enrichSingle(Model $model): Account public function enrichSingle(Model $model): Account
{ {
Log::debug(__METHOD__); Log::debug(__METHOD__);
@@ -76,7 +73,7 @@ class AccountEnrichment implements EnrichmentInterface
return $collection->first(); return $collection->first();
} }
#[Override] #[\Override]
/** /**
* Do the actual enrichment. * Do the actual enrichment.
*/ */
@@ -147,7 +144,7 @@ class AccountEnrichment implements EnrichmentInterface
$metaFields = $this->repository->getMetaValues($this->collection, ['is_multi_currency', 'currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt']); $metaFields = $this->repository->getMetaValues($this->collection, ['is_multi_currency', 'currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt']);
$currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray(); $currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray();
$currencies = []; $currencies = [];
foreach ($this->currencyRepository->getByIds($currencyIds) as $currency) { foreach ($this->currencyRepository->getByIds($currencyIds) as $currency) {
$id = $currency->id; $id = $currency->id;
$currencies[$id] = $currency; $currencies[$id] = $currency;
@@ -177,8 +174,8 @@ class AccountEnrichment implements EnrichmentInterface
$default = $this->default; $default = $this->default;
// get start and end, so the balance difference can be generated. // get start and end, so the balance difference can be generated.
$start = null; $start = null;
$end = null; $end = null;
if (null !== $this->start) { if (null !== $this->start) {
$start = Balance::getAccountBalances($this->collection, $this->start); $start = Balance::getAccountBalances($this->collection, $this->start);
} }
@@ -200,7 +197,7 @@ class AccountEnrichment implements EnrichmentInterface
'balance_difference' => null, 'balance_difference' => null,
]; ];
if (array_key_exists($account->id, $balances)) { if (array_key_exists($account->id, $balances)) {
$set = []; $set = [];
foreach ($balances[$account->id] as $currencyId => $entry) { foreach ($balances[$account->id] as $currencyId => $entry) {
$left = $start[$account->id][$currencyId]['balance'] ?? null; $left = $start[$account->id][$currencyId]['balance'] ?? null;
$right = $end[$account->id][$currencyId]['balance'] ?? null; $right = $end[$account->id][$currencyId]['balance'] ?? null;
@@ -242,11 +239,12 @@ class AccountEnrichment implements EnrichmentInterface
private function getObjectGroups(): void private function getObjectGroups(): void
{ {
$set = DB::table('object_groupables') $set = \DB::table('object_groupables')
->where('object_groupable_type', Account::class) ->where('object_groupable_type', Account::class)
->whereIn('object_groupable_id', $this->collection->pluck('id')->toArray()) ->whereIn('object_groupable_id', $this->collection->pluck('id')->toArray())
->distinct() ->distinct()
->get(['object_groupables.object_groupable_id', 'object_groupables.object_group_id']); ->get(['object_groupables.object_groupable_id', 'object_groupables.object_group_id'])
;
// get the groups: // get the groups:
$groupIds = $set->pluck('object_group_id')->toArray(); $groupIds = $set->pluck('object_group_id')->toArray();
$groups = ObjectGroup::whereIn('id', $groupIds)->get(); $groups = ObjectGroup::whereIn('id', $groupIds)->get();
@@ -256,7 +254,7 @@ class AccountEnrichment implements EnrichmentInterface
$this->objectGroups[$group->id] = $group; $this->objectGroups[$group->id] = $group;
} }
/** @var stdClass $entry */ /** @var \stdClass $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$this->grouped[(int) $entry->object_groupable_id] = (int) $entry->object_group_id; $this->grouped[(int) $entry->object_groupable_id] = (int) $entry->object_group_id;
} }

View File

@@ -77,7 +77,7 @@ trait ExpandsQuery
$config = config('api.valid_api_filters')[$class]; $config = config('api.valid_api_filters')[$class];
$parsed = []; $parsed = [];
foreach ($filters->all() as $filter) { foreach ($filters->all() as $filter) {
$key = $filter->key(); $key = $filter->key();
if (!in_array($key, $config, true)) { if (!in_array($key, $config, true)) {
continue; continue;
} }

View File

@@ -39,8 +39,8 @@ trait FiltersPagination
$pagination['number'] = min(65536, max($pagination['number'], 1)); $pagination['number'] = min(65536, max($pagination['number'], 1));
// clean up page size // clean up page size
$pagination['size'] = (int) ($pagination['size'] ?? $this->getPageSize()); $pagination['size'] = (int) ($pagination['size'] ?? $this->getPageSize());
$pagination['size'] = min(1337, max($pagination['size'], 1)); $pagination['size'] = min(1337, max($pagination['size'], 1));
return $pagination; return $pagination;
} }

View File

@@ -71,14 +71,15 @@ class AccountBalanceCalculator
$balances = []; $balances = [];
$count = 0; $count = 0;
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') $query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNull('transactions.deleted_at') ->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
// this order is the same as GroupCollector, but in the exact reverse. // this order is the same as GroupCollector, but in the exact reverse.
->orderBy('transaction_journals.date', 'asc') ->orderBy('transaction_journals.date', 'asc')
->orderBy('transaction_journals.order', 'desc') ->orderBy('transaction_journals.order', 'desc')
->orderBy('transaction_journals.id', 'asc') ->orderBy('transaction_journals.id', 'asc')
->orderBy('transaction_journals.description', 'asc') ->orderBy('transaction_journals.description', 'asc')
->orderBy('transactions.amount', 'asc'); ->orderBy('transactions.amount', 'asc')
;
if ($accounts->count() > 0) { if ($accounts->count() > 0) {
$query->whereIn('transactions.account_id', $accounts->pluck('id')->toArray()); $query->whereIn('transactions.account_id', $accounts->pluck('id')->toArray());
} }
@@ -87,7 +88,7 @@ class AccountBalanceCalculator
$query->where('transaction_journals.date', '>=', $notBefore); $query->where('transaction_journals.date', '>=', $notBefore);
} }
$set = $query->get(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount']); $set = $query->get(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount']);
// the balance value is an array. // the balance value is an array.
// first entry is the balance, second is the date. // first entry is the balance, second is the date.
@@ -99,8 +100,8 @@ class AccountBalanceCalculator
$balances[$entry->account_id][$entry->transaction_currency_id] ??= [$this->getLatestBalance($entry->account_id, $entry->transaction_currency_id, $notBefore), null]; $balances[$entry->account_id][$entry->transaction_currency_id] ??= [$this->getLatestBalance($entry->account_id, $entry->transaction_currency_id, $notBefore), null];
// before and after are easy: // before and after are easy:
$before = $balances[$entry->account_id][$entry->transaction_currency_id][0]; $before = $balances[$entry->account_id][$entry->transaction_currency_id][0];
$after = bcadd($before, $entry->amount); $after = bcadd($before, $entry->amount);
if (true === $entry->balance_dirty || $accounts->count() > 0) { if (true === $entry->balance_dirty || $accounts->count() > 0) {
// update the transaction: // update the transaction:
$entry->balance_before = $before; $entry->balance_before = $before;
@@ -126,17 +127,18 @@ class AccountBalanceCalculator
return '0'; return '0';
} }
Log::debug(sprintf('getLatestBalance: notBefore date is "%s", calculating', $notBefore->format('Y-m-d'))); Log::debug(sprintf('getLatestBalance: notBefore date is "%s", calculating', $notBefore->format('Y-m-d')));
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') $query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNull('transactions.deleted_at') ->whereNull('transactions.deleted_at')
->where('transaction_journals.transaction_currency_id', $currencyId) ->where('transaction_journals.transaction_currency_id', $currencyId)
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
// this order is the same as GroupCollector // this order is the same as GroupCollector
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC') ->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC') ->orderBy('transaction_journals.description', 'DESC')
->orderBy('transactions.amount', 'DESC') ->orderBy('transactions.amount', 'DESC')
->where('transactions.account_id', $accountId); ->where('transactions.account_id', $accountId)
;
$notBefore->startOfDay(); $notBefore->startOfDay();
$query->where('transaction_journals.date', '<', $notBefore); $query->where('transaction_journals.date', '<', $notBefore);
@@ -168,7 +170,7 @@ class AccountBalanceCalculator
*/ */
foreach ($currencies as $currencyId => $balance) { foreach ($currencies as $currencyId => $balance) {
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
$currency = TransactionCurrency::find($currencyId); $currency = TransactionCurrency::find($currencyId);
if (null === $currency) { if (null === $currency) {
Log::error(sprintf('Could not find currency #%d, will not save account balance.', $currencyId)); Log::error(sprintf('Could not find currency #%d, will not save account balance.', $currencyId));
@@ -196,7 +198,7 @@ class AccountBalanceCalculator
public static function recalculateForJournal(TransactionJournal $transactionJournal): void public static function recalculateForJournal(TransactionJournal $transactionJournal): void
{ {
Log::debug(__METHOD__); Log::debug(__METHOD__);
$object = new self(); $object = new self();
// recalculate the involved accounts: // recalculate the involved accounts:
$accounts = new Collection(); $accounts = new Collection();
@@ -208,9 +210,9 @@ class AccountBalanceCalculator
private function getAccountBalanceByAccount(int $account, int $currency): AccountBalance private function getAccountBalanceByAccount(int $account, int $currency): AccountBalance
{ {
$query = AccountBalance::where('title', 'balance')->where('account_id', $account)->where('transaction_currency_id', $currency); $query = AccountBalance::where('title', 'balance')->where('account_id', $account)->where('transaction_currency_id', $currency);
$entry = $query->first(); $entry = $query->first();
if (null !== $entry) { if (null !== $entry) {
// Log::debug(sprintf('Found account balance "balance" for account #%d and currency #%d: %s', $account, $currency, $entry->balance)); // Log::debug(sprintf('Found account balance "balance" for account #%d and currency #%d: %s', $account, $currency, $entry->balance));
@@ -229,9 +231,9 @@ class AccountBalanceCalculator
private function getAccountBalanceByJournal(string $title, int $account, int $journal, int $currency): AccountBalance private function getAccountBalanceByJournal(string $title, int $account, int $journal, int $currency): AccountBalance
{ {
$query = AccountBalance::where('title', $title)->where('account_id', $account)->where('transaction_journal_id', $journal)->where('transaction_currency_id', $currency); $query = AccountBalance::where('title', $title)->where('account_id', $account)->where('transaction_journal_id', $journal)->where('transaction_currency_id', $currency);
$entry = $query->first(); $entry = $query->first();
if (null !== $entry) { if (null !== $entry) {
return $entry; return $entry;
} }

View File

@@ -49,15 +49,15 @@ class BillDateCalculator
Log::debug(sprintf('Dates must be between %s and %s.', $earliest->format('Y-m-d'), $latest->format('Y-m-d'))); Log::debug(sprintf('Dates must be between %s and %s.', $earliest->format('Y-m-d'), $latest->format('Y-m-d')));
Log::debug(sprintf('Bill started on %s, period is "%s", skip is %d, last paid = "%s".', $billStart->format('Y-m-d'), $period, $skip, $lastPaid?->format('Y-m-d'))); Log::debug(sprintf('Bill started on %s, period is "%s", skip is %d, last paid = "%s".', $billStart->format('Y-m-d'), $period, $skip, $lastPaid?->format('Y-m-d')));
$daysUntilEOM = app('navigation')->daysUntilEndOfMonth($billStart); $daysUntilEOM = app('navigation')->daysUntilEndOfMonth($billStart);
Log::debug(sprintf('For bill start, days until end of month is %d', $daysUntilEOM)); Log::debug(sprintf('For bill start, days until end of month is %d', $daysUntilEOM));
$set = new Collection(); $set = new Collection();
$currentStart = clone $earliest; $currentStart = clone $earliest;
// 2023-06-23 subDay to fix 7655 // 2023-06-23 subDay to fix 7655
$currentStart->subDay(); $currentStart->subDay();
$loop = 0; $loop = 0;
Log::debug('Start of loop'); Log::debug('Start of loop');
while ($currentStart <= $latest) { while ($currentStart <= $latest) {
@@ -107,7 +107,7 @@ class BillDateCalculator
// for the next loop, go to end of period, THEN add day. // for the next loop, go to end of period, THEN add day.
Log::debug('Add one day to nextExpectedMatch/currentStart.'); Log::debug('Add one day to nextExpectedMatch/currentStart.');
$nextExpectedMatch->addDay(); $nextExpectedMatch->addDay();
$currentStart = clone $nextExpectedMatch; $currentStart = clone $nextExpectedMatch;
++$loop; ++$loop;
if ($loop > 12) { if ($loop > 12) {
@@ -117,7 +117,7 @@ class BillDateCalculator
} }
} }
Log::debug('end of loop'); Log::debug('end of loop');
$simple = $set->map( $simple = $set->map(
static function (Carbon $date) { static function (Carbon $date) {
return $date->format('Y-m-d'); return $date->format('Y-m-d');
} }
@@ -142,7 +142,7 @@ class BillDateCalculator
return $billStartDate; return $billStartDate;
} }
$steps = app('navigation')->diffInPeriods($period, $skip, $earliest, $billStartDate); $steps = app('navigation')->diffInPeriods($period, $skip, $earliest, $billStartDate);
if ($steps === $this->diffInMonths) { if ($steps === $this->diffInMonths) {
Log::debug(sprintf('Steps is %d, which is the same as diffInMonths (%d), so we add another 1.', $steps, $this->diffInMonths)); Log::debug(sprintf('Steps is %d, which is the same as diffInMonths (%d), so we add another 1.', $steps, $this->diffInMonths));
++$steps; ++$steps;

View File

@@ -39,7 +39,7 @@ trait ReturnsIntegerIdTrait
protected function id(): Attribute protected function id(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn($value) => (int) $value, get: static fn ($value) => (int) $value,
); );
} }
} }

View File

@@ -37,14 +37,14 @@ trait ReturnsIntegerUserIdTrait
protected function userGroupId(): Attribute protected function userGroupId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn($value) => (int) $value, get: static fn ($value) => (int) $value,
); );
} }
protected function userId(): Attribute protected function userId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn($value) => (int) $value, get: static fn ($value) => (int) $value,
); );
} }
} }

View File

@@ -30,7 +30,6 @@ use FireflyIII\Helpers\Fiscal\FiscalHelperInterface;
use FireflyIII\Support\Calendar\Calculator; use FireflyIII\Support\Calendar\Calculator;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Throwable;
/** /**
* Class Navigation. * Class Navigation.
@@ -77,10 +76,10 @@ class Navigation
if (!array_key_exists($repeatFreq, $functionMap)) { if (!array_key_exists($repeatFreq, $functionMap)) {
Log::error(sprintf( Log::error(sprintf(
'The periodicity %s is unknown. Choose one of available periodicity: %s', 'The periodicity %s is unknown. Choose one of available periodicity: %s',
$repeatFreq, $repeatFreq,
implode(', ', array_keys($functionMap)) implode(', ', array_keys($functionMap))
)); ));
return $theDate; return $theDate;
} }
@@ -94,7 +93,7 @@ class Navigation
return $this->calculator->nextDateByInterval($epoch, $periodicity, $skipInterval); return $this->calculator->nextDateByInterval($epoch, $periodicity, $skipInterval);
} catch (IntervalException $exception) { } catch (IntervalException $exception) {
Log::warning($exception->getMessage(), ['exception' => $exception]); Log::warning($exception->getMessage(), ['exception' => $exception]);
} catch (Throwable $exception) { // @phpstan-ignore-line } catch (\Throwable $exception) { // @phpstan-ignore-line
Log::error($exception->getMessage(), ['exception' => $exception]); Log::error($exception->getMessage(), ['exception' => $exception]);
} }
@@ -111,7 +110,7 @@ class Navigation
if ($end < $start) { if ($end < $start) {
[$start, $end] = [$end, $start]; [$start, $end] = [$end, $start];
} }
$periods = []; $periods = [];
// first, 13 periods of [range] // first, 13 periods of [range]
$loopCount = 0; $loopCount = 0;
$loopDate = clone $end; $loopDate = clone $end;
@@ -161,9 +160,9 @@ class Navigation
public function startOfPeriod(Carbon $theDate, string $repeatFreq): Carbon public function startOfPeriod(Carbon $theDate, string $repeatFreq): Carbon
{ {
$date = clone $theDate; $date = clone $theDate;
// Log::debug(sprintf('Now in startOfPeriod("%s", "%s")', $date->toIso8601String(), $repeatFreq)); // Log::debug(sprintf('Now in startOfPeriod("%s", "%s")', $date->toIso8601String(), $repeatFreq));
$functionMap = [ $functionMap = [
'1D' => 'startOfDay', '1D' => 'startOfDay',
'daily' => 'startOfDay', 'daily' => 'startOfDay',
'1W' => 'startOfWeek', '1W' => 'startOfWeek',
@@ -210,7 +209,7 @@ class Navigation
return $date; return $date;
} }
$result = match ($repeatFreq) { $result = match ($repeatFreq) {
'last7' => $date->subDays(7)->startOfDay(), 'last7' => $date->subDays(7)->startOfDay(),
'last30' => $date->subDays(30)->startOfDay(), 'last30' => $date->subDays(30)->startOfDay(),
'last90' => $date->subDays(90)->startOfDay(), 'last90' => $date->subDays(90)->startOfDay(),
@@ -238,7 +237,7 @@ class Navigation
public function endOfPeriod(Carbon $end, string $repeatFreq): Carbon public function endOfPeriod(Carbon $end, string $repeatFreq): Carbon
{ {
$currentEnd = clone $end; $currentEnd = clone $end;
// Log::debug(sprintf('Now in endOfPeriod("%s", "%s").', $currentEnd->toIso8601String(), $repeatFreq)); // Log::debug(sprintf('Now in endOfPeriod("%s", "%s").', $currentEnd->toIso8601String(), $repeatFreq));
$functionMap = [ $functionMap = [
@@ -272,7 +271,7 @@ class Navigation
Log::debug('Session data available.'); Log::debug('Session data available.');
/** @var Carbon $tStart */ /** @var Carbon $tStart */
$tStart = session('start', today(config('app.timezone'))->startOfMonth()); $tStart = session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $tEnd */ /** @var Carbon $tEnd */
$tEnd = session('end', today(config('app.timezone'))->endOfMonth()); $tEnd = session('end', today(config('app.timezone'))->endOfMonth());
@@ -292,7 +291,7 @@ class Navigation
return $end->endOfMonth(); return $end->endOfMonth();
} }
$result = match ($repeatFreq) { $result = match ($repeatFreq) {
'last7' => $currentEnd->addDays(7)->startOfDay(), 'last7' => $currentEnd->addDays(7)->startOfDay(),
'last30' => $currentEnd->addDays(30)->startOfDay(), 'last30' => $currentEnd->addDays(30)->startOfDay(),
'last90' => $currentEnd->addDays(90)->startOfDay(), 'last90' => $currentEnd->addDays(90)->startOfDay(),
@@ -312,7 +311,7 @@ class Navigation
return $end; return $end;
} }
$function = $functionMap[$repeatFreq]; $function = $functionMap[$repeatFreq];
if (array_key_exists($repeatFreq, $modifierMap)) { if (array_key_exists($repeatFreq, $modifierMap)) {
$currentEnd->{$function}($modifierMap[$repeatFreq]); // @phpstan-ignore-line $currentEnd->{$function}($modifierMap[$repeatFreq]); // @phpstan-ignore-line
@@ -343,13 +342,13 @@ class Navigation
public function diffInPeriods(string $period, int $skip, Carbon $beginning, Carbon $end): int public function diffInPeriods(string $period, int $skip, Carbon $beginning, Carbon $end): int
{ {
Log::debug(sprintf( Log::debug(sprintf(
'diffInPeriods: %s (skip: %d), between %s and %s.', 'diffInPeriods: %s (skip: %d), between %s and %s.',
$period, $period,
$skip, $skip,
$beginning->format('Y-m-d'), $beginning->format('Y-m-d'),
$end->format('Y-m-d') $end->format('Y-m-d')
)); ));
$map = [ $map = [
'daily' => 'diffInDays', 'daily' => 'diffInDays',
'weekly' => 'diffInWeeks', 'weekly' => 'diffInWeeks',
'monthly' => 'diffInMonths', 'monthly' => 'diffInMonths',
@@ -362,7 +361,7 @@ class Navigation
return 1; return 1;
} }
$func = $map[$period]; $func = $map[$period];
// first do the diff // first do the diff
$floatDiff = $beginning->{$func}($end, true); // @phpstan-ignore-line $floatDiff = $beginning->{$func}($end, true); // @phpstan-ignore-line
@@ -377,7 +376,7 @@ class Navigation
} }
// then do ceil() // then do ceil()
$diff = ceil($floatDiff); $diff = ceil($floatDiff);
Log::debug(sprintf('Diff is %f periods (%d rounded up)', $floatDiff, $diff)); Log::debug(sprintf('Diff is %f periods (%d rounded up)', $floatDiff, $diff));
@@ -385,11 +384,11 @@ class Navigation
$parameter = $skip + 1; $parameter = $skip + 1;
$diff = ceil($diff / $parameter) * $parameter; $diff = ceil($diff / $parameter) * $parameter;
Log::debug(sprintf( Log::debug(sprintf(
'diffInPeriods: skip is %d, so param is %d, and diff becomes %d', 'diffInPeriods: skip is %d, so param is %d, and diff becomes %d',
$skip, $skip,
$parameter, $parameter,
$diff $diff
)); ));
} }
return (int) $diff; return (int) $diff;
@@ -414,7 +413,7 @@ class Navigation
'yearly' => 'endOfYear', 'yearly' => 'endOfYear',
]; ];
$currentEnd = clone $theCurrentEnd; $currentEnd = clone $theCurrentEnd;
if (array_key_exists($repeatFreq, $functionMap)) { if (array_key_exists($repeatFreq, $functionMap)) {
$function = $functionMap[$repeatFreq]; $function = $functionMap[$repeatFreq];
@@ -469,7 +468,7 @@ class Navigation
*/ */
public function listOfPeriods(Carbon $start, Carbon $end): array public function listOfPeriods(Carbon $start, Carbon $end): array
{ {
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
// define period to increment // define period to increment
$increment = 'addDay'; $increment = 'addDay';
$format = $this->preferredCarbonFormat($start, $end); $format = $this->preferredCarbonFormat($start, $end);
@@ -486,8 +485,8 @@ class Navigation
$increment = 'addYear'; $increment = 'addYear';
$displayFormat = (string) trans('config.year_js'); $displayFormat = (string) trans('config.year_js');
} }
$begin = clone $start; $begin = clone $start;
$entries = []; $entries = [];
while ($begin < $end) { while ($begin < $end) {
$formatted = $begin->format($format); $formatted = $begin->format($format);
$displayed = $begin->isoFormat($displayFormat); $displayed = $begin->isoFormat($displayFormat);
@@ -649,7 +648,7 @@ class Navigation
public function subtractPeriod(Carbon $theDate, string $repeatFreq, ?int $subtract = null): Carbon public function subtractPeriod(Carbon $theDate, string $repeatFreq, ?int $subtract = null): Carbon
{ {
$subtract ??= 1; $subtract ??= 1;
$date = clone $theDate; $date = clone $theDate;
// 1D 1W 1M 3M 6M 1Y // 1D 1W 1M 3M 6M 1Y
$functionMap = [ $functionMap = [
'1D' => 'subDays', '1D' => 'subDays',
@@ -688,7 +687,7 @@ class Navigation
// this is then subtracted from $theDate (* $subtract). // this is then subtracted from $theDate (* $subtract).
if ('custom' === $repeatFreq) { if ('custom' === $repeatFreq) {
/** @var Carbon $tStart */ /** @var Carbon $tStart */
$tStart = session('start', today(config('app.timezone'))->startOfMonth()); $tStart = session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $tEnd */ /** @var Carbon $tEnd */
$tEnd = session('end', today(config('app.timezone'))->endOfMonth()); $tEnd = session('end', today(config('app.timezone'))->endOfMonth());
@@ -782,7 +781,7 @@ class Navigation
return $fiscalHelper->endOfFiscalYear($end); return $fiscalHelper->endOfFiscalYear($end);
} }
$list = [ $list = [
'last7', 'last7',
'last30', 'last30',
'last90', 'last90',

View File

@@ -24,12 +24,10 @@ declare(strict_types=1);
namespace FireflyIII\Support; namespace FireflyIII\Support;
use ArrayObject;
/** /**
* Class NullArrayObject * Class NullArrayObject
*/ */
class NullArrayObject extends ArrayObject class NullArrayObject extends \ArrayObject
{ {
/** @var null|mixed */ /** @var null|mixed */
public $default; public $default;

View File

@@ -77,15 +77,15 @@ class ParseDateString
public function parseDate(string $date): Carbon public function parseDate(string $date): Carbon
{ {
app('log')->debug(sprintf('parseDate("%s")', $date)); app('log')->debug(sprintf('parseDate("%s")', $date));
$date = strtolower($date); $date = strtolower($date);
// parse keywords: // parse keywords:
if (in_array($date, $this->keywords, true)) { if (in_array($date, $this->keywords, true)) {
return $this->parseKeyword($date); return $this->parseKeyword($date);
} }
// if regex for YYYY-MM-DD: // if regex for YYYY-MM-DD:
$pattern = '/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01])$/'; $pattern = '/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01])$/';
$result = preg_match($pattern, $date); $result = preg_match($pattern, $date);
if (false !== $result && 0 !== $result) { if (false !== $result && 0 !== $result) {
return $this->parseDefaultDate($date); return $this->parseDefaultDate($date);
} }
@@ -178,11 +178,11 @@ class ParseDateString
foreach ($parts as $part) { foreach ($parts as $part) {
app('log')->debug(sprintf('Now parsing part "%s"', $part)); app('log')->debug(sprintf('Now parsing part "%s"', $part));
$part = trim($part); $part = trim($part);
// verify if correct // verify if correct
$pattern = '/[+-]\d+[wqmdy]/'; $pattern = '/[+-]\d+[wqmdy]/';
$result = preg_match($pattern, $part); $result = preg_match($pattern, $part);
if (0 === $result || false === $result) { if (0 === $result || false === $result) {
app('log')->error(sprintf('Part "%s" does not match regular expression. Will be skipped.', $part)); app('log')->error(sprintf('Part "%s" does not match regular expression. Will be skipped.', $part));
@@ -196,7 +196,7 @@ class ParseDateString
continue; continue;
} }
$func = $functions[$direction][$period]; $func = $functions[$direction][$period];
app('log')->debug(sprintf('Will now do %s(%d) on %s', $func, $number, $today->format('Y-m-d'))); app('log')->debug(sprintf('Will now do %s(%d) on %s', $func, $number, $today->format('Y-m-d')));
$today->{$func}($number); // @phpstan-ignore-line $today->{$func}($number); // @phpstan-ignore-line
app('log')->debug(sprintf('Resulting date is %s', $today->format('Y-m-d'))); app('log')->debug(sprintf('Resulting date is %s', $today->format('Y-m-d')));

View File

@@ -47,15 +47,16 @@ class Preferences
} }
return Preference::where('user_id', $user->id) return Preference::where('user_id', $user->id)
->where('name', '!=', 'currencyPreference') ->where('name', '!=', 'currencyPreference')
->where(function (Builder $q) use ($user): void { ->where(function (Builder $q) use ($user): void {
$q->whereNull('user_group_id'); $q->whereNull('user_group_id');
$q->orWhere('user_group_id', $user->user_group_id); $q->orWhere('user_group_id', $user->user_group_id);
}) })
->get(); ->get()
;
} }
public function get(string $name, null | array | bool | int | string $default = null): ?Preference public function get(string $name, null|array|bool|int|string $default = null): ?Preference
{ {
/** @var null|User $user */ /** @var null|User $user */
$user = auth()->user(); $user = auth()->user();
@@ -69,7 +70,7 @@ class Preferences
return $this->getForUser($user, $name, $default); return $this->getForUser($user, $name, $default);
} }
public function getForUser(User $user, string $name, null | array | bool | int | string $default = null): ?Preference public function getForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference
{ {
// don't care about user group ID, except for some specific preferences. // don't care about user group ID, except for some specific preferences.
$userGroupId = $this->getUserGroupId($user, $name); $userGroupId = $this->getUserGroupId($user, $name);
@@ -121,16 +122,16 @@ class Preferences
Cache::put($key, '', 5); Cache::put($key, '', 5);
} }
public function setForUser(User $user, string $name, null | array | bool | int | string $value): Preference public function setForUser(User $user, string $name, null|array|bool|int|string $value): Preference
{ {
$fullName = sprintf('preference%s%s', $user->id, $name); $fullName = sprintf('preference%s%s', $user->id, $name);
$groupId = $this->getUserGroupId($user, $name); $groupId = $this->getUserGroupId($user, $name);
$groupId = 0 === (int) $groupId ? null : (int) $groupId; $groupId = 0 === (int) $groupId ? null : (int) $groupId;
Cache::forget($fullName); Cache::forget($fullName);
/** @var null|Preference $pref */ /** @var null|Preference $pref */
$pref = Preference::where('user_group_id', $groupId)->where('user_id', $user->id)->where('name', $name)->first(['id', 'name', 'data', 'updated_at', 'created_at']); $pref = Preference::where('user_group_id', $groupId)->where('user_id', $user->id)->where('name', $name)->first(['id', 'name', 'data', 'updated_at', 'created_at']);
if (null !== $pref && null === $value) { if (null !== $pref && null === $value) {
$pref->delete(); $pref->delete();
@@ -173,12 +174,13 @@ class Preferences
{ {
$result = []; $result = [];
$preferences = Preference::where('user_id', $user->id) $preferences = Preference::where('user_id', $user->id)
->where(function (Builder $q) use ($user): void { ->where(function (Builder $q) use ($user): void {
$q->whereNull('user_group_id'); $q->whereNull('user_group_id');
$q->orWhere('user_group_id', $user->user_group_id); $q->orWhere('user_group_id', $user->user_group_id);
}) })
->whereIn('name', $list) ->whereIn('name', $list)
->get(['id', 'name', 'data']); ->get(['id', 'name', 'data'])
;
/** @var Preference $preference */ /** @var Preference $preference */
foreach ($preferences as $preference) { foreach ($preferences as $preference) {
@@ -216,7 +218,7 @@ class Preferences
return $result; return $result;
} }
public function getEncryptedForUser(User $user, string $name, null | array | bool | int | string $default = null): ?Preference public function getEncryptedForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference
{ {
$result = $this->getForUser($user, $name, $default); $result = $this->getForUser($user, $name, $default);
if ('' === $result->data) { if ('' === $result->data) {
@@ -237,7 +239,7 @@ class Preferences
return $result; return $result;
} }
public function getFresh(string $name, null | array | bool | int | string $default = null): ?Preference public function getFresh(string $name, null|array|bool|int|string $default = null): ?Preference
{ {
/** @var null|User $user */ /** @var null|User $user */
$user = auth()->user(); $user = auth()->user();
@@ -275,7 +277,7 @@ class Preferences
Session::forget('first'); Session::forget('first');
} }
public function set(string $name, null | array | bool | int | string $value): Preference public function set(string $name, null|array|bool|int|string $value): Preference
{ {
/** @var null|User $user */ /** @var null|User $user */
$user = auth()->user(); $user = auth()->user();

View File

@@ -76,7 +76,7 @@ class BudgetReportGenerator
/** @var Account $account */ /** @var Account $account */
foreach ($this->accounts as $account) { foreach ($this->accounts as $account) {
$accountId = $account->id; $accountId = $account->id;
$this->report[$accountId] ??= [ $this->report[$accountId] ??= [
'name' => $account->name, 'name' => $account->name,
'id' => $account->id, 'id' => $account->id,
@@ -113,18 +113,18 @@ class BudgetReportGenerator
$this->report[$sourceAccountId]['currencies'][$currencyId] $this->report[$sourceAccountId]['currencies'][$currencyId]
??= [ ??= [
'currency_id' => $expenses['currency_id'], 'currency_id' => $expenses['currency_id'],
'currency_symbol' => $expenses['currency_symbol'], 'currency_symbol' => $expenses['currency_symbol'],
'currency_name' => $expenses['currency_name'], 'currency_name' => $expenses['currency_name'],
'currency_decimal_places' => $expenses['currency_decimal_places'], 'currency_decimal_places' => $expenses['currency_decimal_places'],
'budgets' => [], 'budgets' => [],
]; ];
$this->report[$sourceAccountId]['currencies'][$currencyId]['budgets'][$budgetId] $this->report[$sourceAccountId]['currencies'][$currencyId]['budgets'][$budgetId]
??= '0'; ??= '0';
$this->report[$sourceAccountId]['currencies'][$currencyId]['budgets'][$budgetId] $this->report[$sourceAccountId]['currencies'][$currencyId]['budgets'][$budgetId]
= bcadd($this->report[$sourceAccountId]['currencies'][$currencyId]['budgets'][$budgetId], $journal['amount']); = bcadd($this->report[$sourceAccountId]['currencies'][$currencyId]['budgets'][$budgetId], $journal['amount']);
} }
} }
@@ -162,7 +162,7 @@ class BudgetReportGenerator
*/ */
private function processBudget(Budget $budget): void private function processBudget(Budget $budget): void
{ {
$budgetId = $budget->id; $budgetId = $budget->id;
$this->report['budgets'][$budgetId] ??= [ $this->report['budgets'][$budgetId] ??= [
'budget_id' => $budgetId, 'budget_id' => $budgetId,
'budget_name' => $budget->name, 'budget_name' => $budget->name,
@@ -171,7 +171,7 @@ class BudgetReportGenerator
]; ];
// get all budget limits for budget in period: // get all budget limits for budget in period:
$limits = $this->blRepository->getBudgetLimits($budget, $this->start, $this->end); $limits = $this->blRepository->getBudgetLimits($budget, $this->start, $this->end);
/** @var BudgetLimit $limit */ /** @var BudgetLimit $limit */
foreach ($limits as $limit) { foreach ($limits as $limit) {
@@ -184,14 +184,14 @@ class BudgetReportGenerator
*/ */
private function processLimit(Budget $budget, BudgetLimit $limit): void private function processLimit(Budget $budget, BudgetLimit $limit): void
{ {
$budgetId = $budget->id; $budgetId = $budget->id;
$limitId = $limit->id; $limitId = $limit->id;
$limitCurrency = $limit->transactionCurrency ?? $this->currency; $limitCurrency = $limit->transactionCurrency ?? $this->currency;
$currencyId = $limitCurrency->id; $currencyId = $limitCurrency->id;
$expenses = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, $this->accounts, new Collection([$budget])); $expenses = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, $this->accounts, new Collection([$budget]));
$spent = $expenses[$currencyId]['sum'] ?? '0'; $spent = $expenses[$currencyId]['sum'] ?? '0';
$left = -1 === bccomp(bcadd($limit->amount, $spent), '0') ? '0' : bcadd($limit->amount, $spent); $left = -1 === bccomp(bcadd($limit->amount, $spent), '0') ? '0' : bcadd($limit->amount, $spent);
$overspent = 1 === bccomp(bcmul($spent, '-1'), $limit->amount) ? bcadd($spent, $limit->amount) : '0'; $overspent = 1 === bccomp(bcmul($spent, '-1'), $limit->amount) ? bcadd($spent, $limit->amount) : '0';
$this->report['budgets'][$budgetId]['budget_limits'][$limitId] ??= [ $this->report['budgets'][$budgetId]['budget_limits'][$limitId] ??= [
'budget_limit_id' => $limitId, 'budget_limit_id' => $limitId,
@@ -212,17 +212,17 @@ class BudgetReportGenerator
// make sum information: // make sum information:
$this->report['sums'][$currencyId] $this->report['sums'][$currencyId]
??= [ ??= [
'budgeted' => '0', 'budgeted' => '0',
'spent' => '0', 'spent' => '0',
'left' => '0', 'left' => '0',
'overspent' => '0', 'overspent' => '0',
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_code' => $limitCurrency->code, 'currency_code' => $limitCurrency->code,
'currency_name' => $limitCurrency->name, 'currency_name' => $limitCurrency->name,
'currency_symbol' => $limitCurrency->symbol, 'currency_symbol' => $limitCurrency->symbol,
'currency_decimal_places' => $limitCurrency->decimal_places, 'currency_decimal_places' => $limitCurrency->decimal_places,
]; ];
$this->report['sums'][$currencyId]['budgeted'] = bcadd($this->report['sums'][$currencyId]['budgeted'], $limit->amount); $this->report['sums'][$currencyId]['budgeted'] = bcadd($this->report['sums'][$currencyId]['budgeted'], $limit->amount);
$this->report['sums'][$currencyId]['spent'] = bcadd($this->report['sums'][$currencyId]['spent'], $spent); $this->report['sums'][$currencyId]['spent'] = bcadd($this->report['sums'][$currencyId]['spent'], $spent);
$this->report['sums'][$currencyId]['left'] = bcadd($this->report['sums'][$currencyId]['left'], bcadd($limit->amount, $spent)); $this->report['sums'][$currencyId]['left'] = bcadd($this->report['sums'][$currencyId]['left'], bcadd($limit->amount, $spent));
@@ -242,16 +242,16 @@ class BudgetReportGenerator
'budget_limits' => [], 'budget_limits' => [],
]; ];
$noBudget = $this->nbRepository->sumExpenses($this->start, $this->end, $this->accounts); $noBudget = $this->nbRepository->sumExpenses($this->start, $this->end, $this->accounts);
foreach ($noBudget as $noBudgetEntry) { foreach ($noBudget as $noBudgetEntry) {
// currency information: // currency information:
$nbCurrencyId = (int) ($noBudgetEntry['currency_id'] ?? $this->currency->id); $nbCurrencyId = (int) ($noBudgetEntry['currency_id'] ?? $this->currency->id);
$nbCurrencyCode = $noBudgetEntry['currency_code'] ?? $this->currency->code; $nbCurrencyCode = $noBudgetEntry['currency_code'] ?? $this->currency->code;
$nbCurrencyName = $noBudgetEntry['currency_name'] ?? $this->currency->name; $nbCurrencyName = $noBudgetEntry['currency_name'] ?? $this->currency->name;
$nbCurrencySymbol = $noBudgetEntry['currency_symbol'] ?? $this->currency->symbol; $nbCurrencySymbol = $noBudgetEntry['currency_symbol'] ?? $this->currency->symbol;
$nbCurrencyDp = $noBudgetEntry['currency_decimal_places'] ?? $this->currency->decimal_places; $nbCurrencyDp = $noBudgetEntry['currency_decimal_places'] ?? $this->currency->decimal_places;
$this->report['budgets'][0]['budget_limits'][] = [ $this->report['budgets'][0]['budget_limits'][] = [
'budget_limit_id' => null, 'budget_limit_id' => null,
'start_date' => $this->start, 'start_date' => $this->start,
'end_date' => $this->end, 'end_date' => $this->end,
@@ -267,7 +267,7 @@ class BudgetReportGenerator
'currency_symbol' => $nbCurrencySymbol, 'currency_symbol' => $nbCurrencySymbol,
'currency_decimal_places' => $nbCurrencyDp, 'currency_decimal_places' => $nbCurrencyDp,
]; ];
$this->report['sums'][$nbCurrencyId]['spent'] = bcadd($this->report['sums'][$nbCurrencyId]['spent'] ?? '0', $noBudgetEntry['sum']); $this->report['sums'][$nbCurrencyId]['spent'] = bcadd($this->report['sums'][$nbCurrencyId]['spent'] ?? '0', $noBudgetEntry['sum']);
// append currency info because it may be missing: // append currency info because it may be missing:
$this->report['sums'][$nbCurrencyId]['currency_id'] = $nbCurrencyId; $this->report['sums'][$nbCurrencyId]['currency_id'] = $nbCurrencyId;
$this->report['sums'][$nbCurrencyId]['currency_code'] = $nbCurrencyCode; $this->report['sums'][$nbCurrencyId]['currency_code'] = $nbCurrencyCode;
@@ -290,15 +290,15 @@ class BudgetReportGenerator
// make percentages based on total amount. // make percentages based on total amount.
foreach ($this->report['budgets'] as $budgetId => $data) { foreach ($this->report['budgets'] as $budgetId => $data) {
foreach ($data['budget_limits'] as $limitId => $entry) { foreach ($data['budget_limits'] as $limitId => $entry) {
$budgetId = (int) $budgetId; $budgetId = (int) $budgetId;
$limitId = (int) $limitId; $limitId = (int) $limitId;
$currencyId = (int) $entry['currency_id']; $currencyId = (int) $entry['currency_id'];
$spent = $entry['spent']; $spent = $entry['spent'];
$totalSpent = $this->report['sums'][$currencyId]['spent'] ?? '0'; $totalSpent = $this->report['sums'][$currencyId]['spent'] ?? '0';
$spentPct = '0'; $spentPct = '0';
$budgeted = $entry['budgeted']; $budgeted = $entry['budgeted'];
$totalBudgeted = $this->report['sums'][$currencyId]['budgeted'] ?? '0'; $totalBudgeted = $this->report['sums'][$currencyId]['budgeted'] ?? '0';
$budgetedPct = '0'; $budgetedPct = '0';
if (0 !== bccomp($spent, '0') && 0 !== bccomp($totalSpent, '0')) { if (0 !== bccomp($spent, '0') && 0 !== bccomp($totalSpent, '0')) {
$spentPct = round((float) bcmul(bcdiv($spent, $totalSpent), '100')); $spentPct = round((float) bcmul(bcdiv($spent, $totalSpent), '100'));
@@ -306,7 +306,7 @@ class BudgetReportGenerator
if (0 !== bccomp($budgeted, '0') && 0 !== bccomp($totalBudgeted, '0')) { if (0 !== bccomp($budgeted, '0') && 0 !== bccomp($totalBudgeted, '0')) {
$budgetedPct = round((float) bcmul(bcdiv($budgeted, $totalBudgeted), '100')); $budgetedPct = round((float) bcmul(bcdiv($budgeted, $totalBudgeted), '100'));
} }
$this->report['sums'][$currencyId]['budgeted'] ??= '0'; $this->report['sums'][$currencyId]['budgeted'] ??= '0';
$this->report['budgets'][$budgetId]['budget_limits'][$limitId]['spent_pct'] = $spentPct; $this->report['budgets'][$budgetId]['budget_limits'][$limitId]['spent_pct'] = $spentPct;
$this->report['budgets'][$budgetId]['budget_limits'][$limitId]['budgeted_pct'] = $budgetedPct; $this->report['budgets'][$budgetId]['budget_limits'][$limitId]['budgeted_pct'] = $budgetedPct;
} }

View File

@@ -62,17 +62,17 @@ class CategoryReportGenerator
*/ */
public function operations(): void public function operations(): void
{ {
$earnedWith = $this->opsRepository->listIncome($this->start, $this->end, $this->accounts); $earnedWith = $this->opsRepository->listIncome($this->start, $this->end, $this->accounts);
$spentWith = $this->opsRepository->listExpenses($this->start, $this->end, $this->accounts); $spentWith = $this->opsRepository->listExpenses($this->start, $this->end, $this->accounts);
// also transferred out and transferred into these accounts in this category: // also transferred out and transferred into these accounts in this category:
$transferredIn = $this->opsRepository->listTransferredIn($this->start, $this->end, $this->accounts); $transferredIn = $this->opsRepository->listTransferredIn($this->start, $this->end, $this->accounts);
$transferredOut = $this->opsRepository->listTransferredOut($this->start, $this->end, $this->accounts); $transferredOut = $this->opsRepository->listTransferredOut($this->start, $this->end, $this->accounts);
$earnedWithout = $this->noCatRepository->listIncome($this->start, $this->end, $this->accounts); $earnedWithout = $this->noCatRepository->listIncome($this->start, $this->end, $this->accounts);
$spentWithout = $this->noCatRepository->listExpenses($this->start, $this->end, $this->accounts); $spentWithout = $this->noCatRepository->listExpenses($this->start, $this->end, $this->accounts);
$this->report = [ $this->report = [
'categories' => [], 'categories' => [],
'sums' => [], 'sums' => [],
]; ];
@@ -121,7 +121,7 @@ class CategoryReportGenerator
private function processCategoryRow(int $currencyId, array $currencyRow, int $categoryId, array $categoryRow): void private function processCategoryRow(int $currencyId, array $currencyRow, int $categoryId, array $categoryRow): void
{ {
$key = sprintf('%s-%s', $currencyId, $categoryId); $key = sprintf('%s-%s', $currencyId, $categoryId);
$this->report['categories'][$key] ??= [ $this->report['categories'][$key] ??= [
'id' => $categoryId, 'id' => $categoryId,
'title' => $categoryRow['name'], 'title' => $categoryRow['name'],
@@ -137,9 +137,9 @@ class CategoryReportGenerator
// loop journals: // loop journals:
foreach ($categoryRow['transaction_journals'] as $journal) { foreach ($categoryRow['transaction_journals'] as $journal) {
// sum of sums // sum of sums
$this->report['sums'][$currencyId]['sum'] = bcadd($this->report['sums'][$currencyId]['sum'], $journal['amount']); $this->report['sums'][$currencyId]['sum'] = bcadd($this->report['sums'][$currencyId]['sum'], $journal['amount']);
// sum of spent: // sum of spent:
$this->report['sums'][$currencyId]['spent'] = -1 === bccomp($journal['amount'], '0') ? bcadd( $this->report['sums'][$currencyId]['spent'] = -1 === bccomp($journal['amount'], '0') ? bcadd(
$this->report['sums'][$currencyId]['spent'], $this->report['sums'][$currencyId]['spent'],
$journal['amount'] $journal['amount']
) : $this->report['sums'][$currencyId]['spent']; ) : $this->report['sums'][$currencyId]['spent'];
@@ -150,14 +150,14 @@ class CategoryReportGenerator
) : $this->report['sums'][$currencyId]['earned']; ) : $this->report['sums'][$currencyId]['earned'];
// sum of category // sum of category
$this->report['categories'][$key]['sum'] = bcadd($this->report['categories'][$key]['sum'], $journal['amount']); $this->report['categories'][$key]['sum'] = bcadd($this->report['categories'][$key]['sum'], $journal['amount']);
// total spent in category // total spent in category
$this->report['categories'][$key]['spent'] = -1 === bccomp($journal['amount'], '0') ? bcadd( $this->report['categories'][$key]['spent'] = -1 === bccomp($journal['amount'], '0') ? bcadd(
$this->report['categories'][$key]['spent'], $this->report['categories'][$key]['spent'],
$journal['amount'] $journal['amount']
) : $this->report['categories'][$key]['spent']; ) : $this->report['categories'][$key]['spent'];
// total earned in category // total earned in category
$this->report['categories'][$key]['earned'] = 1 === bccomp($journal['amount'], '0') ? bcadd( $this->report['categories'][$key]['earned'] = 1 === bccomp($journal['amount'], '0') ? bcadd(
$this->report['categories'][$key]['earned'], $this->report['categories'][$key]['earned'],
$journal['amount'] $journal['amount']
) : $this->report['categories'][$key]['earned']; ) : $this->report['categories'][$key]['earned'];

View File

@@ -82,8 +82,8 @@ trait CalculateRangeOccurrences
*/ */
protected function getNdomInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array protected function getNdomInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array
{ {
$return = []; $return = [];
$attempts = 0; $attempts = 0;
$start->startOfMonth(); $start->startOfMonth();
// this feels a bit like a cop out but why reinvent the wheel? // this feels a bit like a cop out but why reinvent the wheel?
$counters = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth']; $counters = [1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth'];
@@ -108,12 +108,12 @@ trait CalculateRangeOccurrences
*/ */
protected function getWeeklyInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array protected function getWeeklyInRange(Carbon $start, Carbon $end, int $skipMod, string $moment): array
{ {
$return = []; $return = [];
$attempts = 0; $attempts = 0;
app('log')->debug('Rep is weekly.'); app('log')->debug('Rep is weekly.');
// monday = 1 // monday = 1
// sunday = 7 // sunday = 7
$dayOfWeek = (int) $moment; $dayOfWeek = (int) $moment;
app('log')->debug(sprintf('DoW in repetition is %d, in mutator is %d', $dayOfWeek, $start->dayOfWeekIso)); app('log')->debug(sprintf('DoW in repetition is %d, in mutator is %d', $dayOfWeek, $start->dayOfWeekIso));
if ($start->dayOfWeekIso > $dayOfWeek) { if ($start->dayOfWeekIso > $dayOfWeek) {
// day has already passed this week, add one week: // day has already passed this week, add one week:
@@ -154,8 +154,8 @@ trait CalculateRangeOccurrences
} }
// is $date between $start and $end? // is $date between $start and $end?
$obj = clone $date; $obj = clone $date;
$count = 0; $count = 0;
while ($obj <= $end && $obj >= $start && $count < 10) { while ($obj <= $end && $obj >= $start && $count < 10) {
if (0 === $attempts % $skipMod) { if (0 === $attempts % $skipMod) {
$return[] = clone $obj; $return[] = clone $obj;

View File

@@ -89,10 +89,10 @@ trait CalculateXOccurrences
*/ */
protected function getXNDomOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array protected function getXNDomOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array
{ {
$return = []; $return = [];
$total = 0; $total = 0;
$attempts = 0; $attempts = 0;
$mutator = clone $date; $mutator = clone $date;
$mutator->addDay(); // always assume today has passed. $mutator->addDay(); // always assume today has passed.
$mutator->startOfMonth(); $mutator->startOfMonth();
// this feels a bit like a cop out but why reinvent the wheel? // this feels a bit like a cop out but why reinvent the wheel?
@@ -120,14 +120,14 @@ trait CalculateXOccurrences
*/ */
protected function getXWeeklyOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array protected function getXWeeklyOccurrences(Carbon $date, int $count, int $skipMod, string $moment): array
{ {
$return = []; $return = [];
$total = 0; $total = 0;
$attempts = 0; $attempts = 0;
$mutator = clone $date; $mutator = clone $date;
// monday = 1 // monday = 1
// sunday = 7 // sunday = 7
$mutator->addDay(); // always assume today has passed. $mutator->addDay(); // always assume today has passed.
$dayOfWeek = (int) $moment; $dayOfWeek = (int) $moment;
if ($mutator->dayOfWeekIso > $dayOfWeek) { if ($mutator->dayOfWeekIso > $dayOfWeek) {
// day has already passed this week, add one week: // day has already passed this week, add one week:
$mutator->addWeek(); $mutator->addWeek();
@@ -164,7 +164,7 @@ trait CalculateXOccurrences
if ($mutator > $date) { if ($mutator > $date) {
$date->addYear(); $date->addYear();
} }
$obj = clone $date; $obj = clone $date;
while ($total < $count) { while ($total < $count) {
if (0 === $attempts % $skipMod) { if (0 === $attempts % $skipMod) {
$return[] = clone $obj; $return[] = clone $obj;

View File

@@ -86,7 +86,7 @@ trait CalculateXOccurrencesSince
++$total; ++$total;
} }
++$attempts; ++$attempts;
$mutator = $mutator->endOfMonth()->addDay(); $mutator = $mutator->endOfMonth()->addDay();
} }
return $return; return $return;
@@ -101,10 +101,10 @@ trait CalculateXOccurrencesSince
protected function getXNDomOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array protected function getXNDomOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
$return = []; $return = [];
$total = 0; $total = 0;
$attempts = 0; $attempts = 0;
$mutator = clone $date; $mutator = clone $date;
$mutator->addDay(); // always assume today has passed. $mutator->addDay(); // always assume today has passed.
$mutator->startOfMonth(); $mutator->startOfMonth();
// this feels a bit like a cop out but why reinvent the wheel? // this feels a bit like a cop out but why reinvent the wheel?
@@ -135,15 +135,15 @@ trait CalculateXOccurrencesSince
protected function getXWeeklyOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array protected function getXWeeklyOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
$return = []; $return = [];
$total = 0; $total = 0;
$attempts = 0; $attempts = 0;
$mutator = clone $date; $mutator = clone $date;
// monday = 1 // monday = 1
// sunday = 7 // sunday = 7
// Removed assumption today has passed, see issue https://github.com/firefly-iii/firefly-iii/issues/4798 // Removed assumption today has passed, see issue https://github.com/firefly-iii/firefly-iii/issues/4798
// $mutator->addDay(); // always assume today has passed. // $mutator->addDay(); // always assume today has passed.
$dayOfWeek = (int) $moment; $dayOfWeek = (int) $moment;
if ($mutator->dayOfWeekIso > $dayOfWeek) { if ($mutator->dayOfWeekIso > $dayOfWeek) {
// day has already passed this week, add one week: // day has already passed this week, add one week:
$mutator->addWeek(); $mutator->addWeek();
@@ -187,7 +187,7 @@ trait CalculateXOccurrencesSince
$date->addYear(); $date->addYear();
app('log')->debug(sprintf('Date is now %s', $date->format('Y-m-d'))); app('log')->debug(sprintf('Date is now %s', $date->format('Y-m-d')));
} }
$obj = clone $date; $obj = clone $date;
while ($total < $count) { while ($total < $count) {
app('log')->debug(sprintf('total (%d) < count (%d) so go.', $total, $count)); app('log')->debug(sprintf('total (%d) < count (%d) so go.', $total, $count));
app('log')->debug(sprintf('attempts (%d) %% skipmod (%d) === %d', $attempts, $skipMod, $attempts % $skipMod)); app('log')->debug(sprintf('attempts (%d) %% skipmod (%d) === %d', $attempts, $skipMod, $attempts % $skipMod));

View File

@@ -44,7 +44,7 @@ trait FiltersWeekends
return $dates; return $dates;
} }
$return = []; $return = [];
/** @var Carbon $date */ /** @var Carbon $date */
foreach ($dates as $date) { foreach ($dates as $date) {
@@ -58,7 +58,7 @@ trait FiltersWeekends
// is weekend and must set back to Friday? // is weekend and must set back to Friday?
if (RecurrenceRepetition::WEEKEND_TO_FRIDAY === $repetition->weekend) { if (RecurrenceRepetition::WEEKEND_TO_FRIDAY === $repetition->weekend) {
$clone = clone $date; $clone = clone $date;
$clone->addDays(5 - $date->dayOfWeekIso); $clone->addDays(5 - $date->dayOfWeekIso);
app('log')->debug( app('log')->debug(
sprintf('Date is %s, and this is in the weekend, so corrected to %s (Friday).', $date->format('D d M Y'), $clone->format('D d M Y')) sprintf('Date is %s, and this is in the weekend, so corrected to %s (Friday).', $date->format('D d M Y'), $clone->format('D d M Y'))
@@ -70,7 +70,7 @@ trait FiltersWeekends
// postpone to Monday? // postpone to Monday?
if (RecurrenceRepetition::WEEKEND_TO_MONDAY === $repetition->weekend) { if (RecurrenceRepetition::WEEKEND_TO_MONDAY === $repetition->weekend) {
$clone = clone $date; $clone = clone $date;
$clone->addDays(8 - $date->dayOfWeekIso); $clone->addDays(8 - $date->dayOfWeekIso);
app('log')->debug( app('log')->debug(
sprintf('Date is %s, and this is in the weekend, so corrected to %s (Monday).', $date->format('D d M Y'), $clone->format('D d M Y')) sprintf('Date is %s, and this is in the weekend, so corrected to %s (Monday).', $date->format('D d M Y'), $clone->format('D d M Y'))

View File

@@ -54,10 +54,10 @@ trait UserGroupTrait
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
public function setUser(null | Authenticatable | User $user): void public function setUser(null|Authenticatable|User $user): void
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;
if (null === $user->userGroup) { if (null === $user->userGroup) {
throw new FireflyException(sprintf('User #%d has no user group.', $user->id)); throw new FireflyException(sprintf('User #%d has no user group.', $user->id));
} }
@@ -70,15 +70,16 @@ trait UserGroupTrait
*/ */
public function setUserGroupById(int $userGroupId): void public function setUserGroupById(int $userGroupId): void
{ {
$memberships = GroupMembership::where('user_id', $this->user->id) $memberships = GroupMembership::where('user_id', $this->user->id)
->where('user_group_id', $userGroupId) ->where('user_group_id', $userGroupId)
->count(); ->count()
;
if (0 === $memberships) { if (0 === $memberships) {
throw new FireflyException(sprintf('User #%d has no access to administration #%d', $this->user->id, $userGroupId)); throw new FireflyException(sprintf('User #%d has no access to administration #%d', $this->user->id, $userGroupId));
} }
/** @var null|UserGroup $userGroup */ /** @var null|UserGroup $userGroup */
$userGroup = UserGroup::find($userGroupId); $userGroup = UserGroup::find($userGroupId);
if (null === $userGroup) { if (null === $userGroup) {
throw new FireflyException(sprintf('Cannot find administration for user #%d', $this->user->id)); throw new FireflyException(sprintf('Cannot find administration for user #%d', $this->user->id));
} }

View File

@@ -82,12 +82,12 @@ trait AppendsLocationData
$data['latitude'] = null; $data['latitude'] = null;
$data['zoom_level'] = null; $data['zoom_level'] = null;
$longitudeKey = $this->getLocationKey($prefix, 'longitude'); $longitudeKey = $this->getLocationKey($prefix, 'longitude');
$latitudeKey = $this->getLocationKey($prefix, 'latitude'); $latitudeKey = $this->getLocationKey($prefix, 'latitude');
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level'); $zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
$isValidPOST = $this->isValidPost($prefix); $isValidPOST = $this->isValidPost($prefix);
$isValidPUT = $this->isValidPUT($prefix); $isValidPUT = $this->isValidPUT($prefix);
$isValidEmptyPUT = $this->isValidEmptyPUT($prefix); $isValidEmptyPUT = $this->isValidEmptyPUT($prefix);
// for a POST (store), all fields must be present and not NULL. // for a POST (store), all fields must be present and not NULL.
if ($isValidPOST) { if ($isValidPOST) {
@@ -245,9 +245,9 @@ trait AppendsLocationData
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level'); $zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
return ( return (
null === $this->get($longitudeKey) null === $this->get($longitudeKey)
&& null === $this->get($latitudeKey) && null === $this->get($latitudeKey)
&& null === $this->get($zoomLevelKey)) && null === $this->get($zoomLevelKey))
&& ( && (
'PUT' === $this->method() 'PUT' === $this->method()
|| ('POST' === $this->method() && $this->routeIs('*.update')) || ('POST' === $this->method() && $this->routeIs('*.update'))

View File

@@ -40,7 +40,7 @@ trait ChecksLogin
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
// Only allow logged-in users // Only allow logged-in users
$check = auth()->check(); $check = auth()->check();
if (!$check) { if (!$check) {
return false; return false;
} }
@@ -79,7 +79,7 @@ trait ChecksLogin
public function getUserGroup(): ?UserGroup public function getUserGroup(): ?UserGroup
{ {
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
app('log')->debug('Now in getUserGroup()'); app('log')->debug('Now in getUserGroup()');
/** @var null|UserGroup $userGroup */ /** @var null|UserGroup $userGroup */
@@ -91,7 +91,7 @@ trait ChecksLogin
app('log')->debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id)); app('log')->debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id));
$userGroupId = (int) $user->user_group_id; $userGroupId = (int) $user->user_group_id;
} }
$userGroup = UserGroup::find($userGroupId); $userGroup = UserGroup::find($userGroupId);
if (null === $userGroup) { if (null === $userGroup) {
app('log')->error(sprintf('Request class has user_group_id (#%d), but group does not exist.', $userGroupId)); app('log')->error(sprintf('Request class has user_group_id (#%d), but group does not exist.', $userGroupId));

View File

@@ -27,6 +27,4 @@ namespace FireflyIII\Support\Request;
/** /**
* Trait ConvertAPIDataTypes * Trait ConvertAPIDataTypes
*/ */
trait ConvertAPIDataTypes trait ConvertAPIDataTypes {}
{
}

View File

@@ -38,13 +38,13 @@ trait GetFilterInstructions
return []; return [];
} }
foreach ($set as $info) { foreach ($set as $info) {
$column = $info['column'] ?? 'NOPE'; $column = $info['column'] ?? 'NOPE';
$filterValue = (string) ($info['filter'] ?? self::INVALID_FILTER); $filterValue = (string) ($info['filter'] ?? self::INVALID_FILTER);
if (false === in_array($column, $allowed, true)) { if (false === in_array($column, $allowed, true)) {
// skip invalid column // skip invalid column
continue; continue;
} }
$filterType = $config[$column] ?? false; $filterType = $config[$column] ?? false;
switch ($filterType) { switch ($filterType) {
default: default:

View File

@@ -35,8 +35,8 @@ trait GetSortInstructions
return []; return [];
} }
foreach ($set as $info) { foreach ($set as $info) {
$column = $info['column'] ?? 'NOPE'; $column = $info['column'] ?? 'NOPE';
$direction = $info['direction'] ?? 'NOPE'; $direction = $info['direction'] ?? 'NOPE';
if ('asc' !== $direction && 'desc' !== $direction) { if ('asc' !== $direction && 'desc' !== $direction) {
// skip invalid direction // skip invalid direction
continue; continue;

View File

@@ -35,16 +35,16 @@ use Illuminate\Support\Collection;
class AccountSearch implements GenericSearchInterface class AccountSearch implements GenericSearchInterface
{ {
/** @var string */ /** @var string */
public const string SEARCH_ALL = 'all'; public const string SEARCH_ALL = 'all';
/** @var string */ /** @var string */
public const string SEARCH_IBAN = 'iban'; public const string SEARCH_IBAN = 'iban';
/** @var string */ /** @var string */
public const string SEARCH_ID = 'id'; public const string SEARCH_ID = 'id';
/** @var string */ /** @var string */
public const string SEARCH_NAME = 'name'; public const string SEARCH_NAME = 'name';
/** @var string */ /** @var string */
public const string SEARCH_NUMBER = 'number'; public const string SEARCH_NUMBER = 'number';
@@ -61,9 +61,10 @@ class AccountSearch implements GenericSearchInterface
public function search(): Collection public function search(): Collection
{ {
$searchQuery = $this->user->accounts() $searchQuery = $this->user->accounts()
->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id') ->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->whereIn('account_types.type', $this->types); ->whereIn('account_types.type', $this->types)
;
$like = sprintf('%%%s%%', $this->query); $like = sprintf('%%%s%%', $this->query);
$originalQuery = $this->query; $originalQuery = $this->query;
@@ -134,7 +135,7 @@ class AccountSearch implements GenericSearchInterface
$this->types = $types; $this->types = $types;
} }
public function setUser(null | Authenticatable | User $user): void public function setUser(null|Authenticatable|User $user): void
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -57,8 +57,6 @@ use Gdbots\QueryParser\Node\Word;
use Gdbots\QueryParser\QueryParser; use Gdbots\QueryParser\QueryParser;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use LogicException;
use TypeError;
/** /**
* Class OperatorQuerySearch * Class OperatorQuerySearch
@@ -151,7 +149,7 @@ class OperatorQuerySearch implements SearchInterface
try { try {
$query1 = $parser->parse($query); $query1 = $parser->parse($query);
} catch (LogicException | TypeError $e) { } catch (\LogicException|\TypeError $e) {
app('log')->error($e->getMessage()); app('log')->error($e->getMessage());
app('log')->error(sprintf('Could not parse search: "%s".', $query)); app('log')->error(sprintf('Could not parse search: "%s".', $query));
@@ -203,7 +201,7 @@ class OperatorQuerySearch implements SearchInterface
case Emoticon::class: case Emoticon::class:
case Emoji::class: case Emoji::class:
case Mention::class: case Mention::class:
$allWords = (string) $searchNode->getValue(); $allWords = (string) $searchNode->getValue();
app('log')->debug(sprintf('Add words "%s" to search string, because Node class is "%s"', $allWords, $class)); app('log')->debug(sprintf('Add words "%s" to search string, because Node class is "%s"', $allWords, $class));
$this->words[] = $allWords; $this->words[] = $allWords;
@@ -214,10 +212,10 @@ class OperatorQuerySearch implements SearchInterface
/** @var Field $searchNode */ /** @var Field $searchNode */
// used to search for x:y // used to search for x:y
$operator = strtolower($searchNode->getValue()); $operator = strtolower($searchNode->getValue());
$value = $searchNode->getNode()->getValue(); $value = $searchNode->getNode()->getValue();
$prohibited = BoolOperator::PROHIBITED === $searchNode->getBoolOperator(); $prohibited = BoolOperator::PROHIBITED === $searchNode->getBoolOperator();
$context = config(sprintf('search.operators.%s.needs_context', $operator)); $context = config(sprintf('search.operators.%s.needs_context', $operator));
// is an operator that needs no context, and value is false, then prohibited = true. // is an operator that needs no context, and value is false, then prohibited = true.
if ('false' === $value && in_array($operator, $this->validOperators, true) && false === $context && !$prohibited) { if ('false' === $value && in_array($operator, $this->validOperators, true) && false === $context && !$prohibited) {
@@ -277,15 +275,15 @@ class OperatorQuerySearch implements SearchInterface
throw new FireflyException(sprintf('Unsupported search operator: "%s"', $operator)); throw new FireflyException(sprintf('Unsupported search operator: "%s"', $operator));
// some search operators are ignored, basically: // some search operators are ignored, basically:
case 'user_action': case 'user_action':
app('log')->info(sprintf('Ignore search operator "%s"', $operator)); app('log')->info(sprintf('Ignore search operator "%s"', $operator));
return false; return false;
// //
// all account related searches: // all account related searches:
// //
case 'account_is': case 'account_is':
$this->searchAccount($value, SearchDirection::BOTH, StringPosition::IS); $this->searchAccount($value, SearchDirection::BOTH, StringPosition::IS);
@@ -447,7 +445,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'source_account_id': case 'source_account_id':
$account = $this->accountRepository->find((int) $value); $account = $this->accountRepository->find((int) $value);
if (null !== $account) { if (null !== $account) {
$this->collector->setSourceAccounts(new Collection([$account])); $this->collector->setSourceAccounts(new Collection([$account]));
} }
@@ -459,7 +457,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-source_account_id': case '-source_account_id':
$account = $this->accountRepository->find((int) $value); $account = $this->accountRepository->find((int) $value);
if (null !== $account) { if (null !== $account) {
$this->collector->excludeSourceAccounts(new Collection([$account])); $this->collector->excludeSourceAccounts(new Collection([$account]));
} }
@@ -471,25 +469,25 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'journal_id': case 'journal_id':
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->setJournalIds($parts); $this->collector->setJournalIds($parts);
break; break;
case '-journal_id': case '-journal_id':
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->excludeJournalIds($parts); $this->collector->excludeJournalIds($parts);
break; break;
case 'id': case 'id':
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->setIds($parts); $this->collector->setIds($parts);
break; break;
case '-id': case '-id':
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->excludeIds($parts); $this->collector->excludeIds($parts);
break; break;
@@ -575,7 +573,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'destination_account_id': case 'destination_account_id':
$account = $this->accountRepository->find((int) $value); $account = $this->accountRepository->find((int) $value);
if (null !== $account) { if (null !== $account) {
$this->collector->setDestinationAccounts(new Collection([$account])); $this->collector->setDestinationAccounts(new Collection([$account]));
} }
@@ -586,7 +584,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-destination_account_id': case '-destination_account_id':
$account = $this->accountRepository->find((int) $value); $account = $this->accountRepository->find((int) $value);
if (null !== $account) { if (null !== $account) {
$this->collector->excludeDestinationAccounts(new Collection([$account])); $this->collector->excludeDestinationAccounts(new Collection([$account]));
} }
@@ -597,8 +595,8 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'account_id': case 'account_id':
$parts = explode(',', $value); $parts = explode(',', $value);
$collection = new Collection(); $collection = new Collection();
foreach ($parts as $accountId) { foreach ($parts as $accountId) {
$account = $this->accountRepository->find((int) $accountId); $account = $this->accountRepository->find((int) $accountId);
if (null !== $account) { if (null !== $account) {
@@ -615,8 +613,8 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-account_id': case '-account_id':
$parts = explode(',', $value); $parts = explode(',', $value);
$collection = new Collection(); $collection = new Collection();
foreach ($parts as $accountId) { foreach ($parts as $accountId) {
$account = $this->accountRepository->find((int) $accountId); $account = $this->accountRepository->find((int) $accountId);
if (null !== $account) { if (null !== $account) {
@@ -632,48 +630,48 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// cash account // cash account
// //
case 'source_is_cash': case 'source_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->setSourceAccounts(new Collection([$account])); $this->collector->setSourceAccounts(new Collection([$account]));
break; break;
case '-source_is_cash': case '-source_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->excludeSourceAccounts(new Collection([$account])); $this->collector->excludeSourceAccounts(new Collection([$account]));
break; break;
case 'destination_is_cash': case 'destination_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->setDestinationAccounts(new Collection([$account])); $this->collector->setDestinationAccounts(new Collection([$account]));
break; break;
case '-destination_is_cash': case '-destination_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->excludeDestinationAccounts(new Collection([$account])); $this->collector->excludeDestinationAccounts(new Collection([$account]));
break; break;
case 'account_is_cash': case 'account_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->setAccounts(new Collection([$account])); $this->collector->setAccounts(new Collection([$account]));
break; break;
case '-account_is_cash': case '-account_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->excludeAccounts(new Collection([$account])); $this->collector->excludeAccounts(new Collection([$account]));
break; break;
// //
// description // description
// //
case 'description_starts': case 'description_starts':
$this->collector->descriptionStarts([$value]); $this->collector->descriptionStarts([$value]);
@@ -695,7 +693,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'description_contains': case 'description_contains':
$this->words[] = $value; $this->words[] = $value;
return false; return false;
@@ -714,11 +712,11 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// currency // currency
// //
case 'currency_is': case 'currency_is':
$currency = $this->findCurrency($value); $currency = $this->findCurrency($value);
if (null !== $currency) { if (null !== $currency) {
$this->collector->setCurrency($currency); $this->collector->setCurrency($currency);
} }
@@ -729,7 +727,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-currency_is': case '-currency_is':
$currency = $this->findCurrency($value); $currency = $this->findCurrency($value);
if (null !== $currency) { if (null !== $currency) {
$this->collector->excludeCurrency($currency); $this->collector->excludeCurrency($currency);
} }
@@ -740,7 +738,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'foreign_currency_is': case 'foreign_currency_is':
$currency = $this->findCurrency($value); $currency = $this->findCurrency($value);
if (null !== $currency) { if (null !== $currency) {
$this->collector->setForeignCurrency($currency); $this->collector->setForeignCurrency($currency);
} }
@@ -751,7 +749,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-foreign_currency_is': case '-foreign_currency_is':
$currency = $this->findCurrency($value); $currency = $this->findCurrency($value);
if (null !== $currency) { if (null !== $currency) {
$this->collector->excludeForeignCurrency($currency); $this->collector->excludeForeignCurrency($currency);
} }
@@ -761,9 +759,9 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// attachments // attachments
// //
case 'has_attachments': case 'has_attachments':
case '-has_no_attachments': case '-has_no_attachments':
app('log')->debug('Set collector to filter on attachments.'); app('log')->debug('Set collector to filter on attachments.');
@@ -778,8 +776,8 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// categories // categories
case '-has_any_category': case '-has_any_category':
case 'has_no_category': case 'has_no_category':
$this->collector->withoutCategory(); $this->collector->withoutCategory();
@@ -793,7 +791,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'category_is': case 'category_is':
$category = $this->categoryRepository->findByName($value); $category = $this->categoryRepository->findByName($value);
if (null !== $category) { if (null !== $category) {
$this->collector->setCategory($category); $this->collector->setCategory($category);
@@ -804,7 +802,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-category_is': case '-category_is':
$category = $this->categoryRepository->findByName($value); $category = $this->categoryRepository->findByName($value);
if (null !== $category) { if (null !== $category) {
$this->collector->excludeCategory($category); $this->collector->excludeCategory($category);
@@ -814,7 +812,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'category_ends': case 'category_ends':
$result = $this->categoryRepository->categoryEndsWith($value, 1337); $result = $this->categoryRepository->categoryEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setCategories($result); $this->collector->setCategories($result);
} }
@@ -825,7 +823,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-category_ends': case '-category_ends':
$result = $this->categoryRepository->categoryEndsWith($value, 1337); $result = $this->categoryRepository->categoryEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeCategories($result); $this->collector->excludeCategories($result);
} }
@@ -836,7 +834,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'category_starts': case 'category_starts':
$result = $this->categoryRepository->categoryStartsWith($value, 1337); $result = $this->categoryRepository->categoryStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setCategories($result); $this->collector->setCategories($result);
} }
@@ -847,7 +845,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-category_starts': case '-category_starts':
$result = $this->categoryRepository->categoryStartsWith($value, 1337); $result = $this->categoryRepository->categoryStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeCategories($result); $this->collector->excludeCategories($result);
} }
@@ -858,7 +856,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'category_contains': case 'category_contains':
$result = $this->categoryRepository->searchCategory($value, 1337); $result = $this->categoryRepository->searchCategory($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setCategories($result); $this->collector->setCategories($result);
} }
@@ -869,7 +867,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-category_contains': case '-category_contains':
$result = $this->categoryRepository->searchCategory($value, 1337); $result = $this->categoryRepository->searchCategory($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeCategories($result); $this->collector->excludeCategories($result);
} }
@@ -879,9 +877,9 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// budgets // budgets
// //
case '-has_any_budget': case '-has_any_budget':
case 'has_no_budget': case 'has_no_budget':
$this->collector->withoutBudget(); $this->collector->withoutBudget();
@@ -895,7 +893,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'budget_contains': case 'budget_contains':
$result = $this->budgetRepository->searchBudget($value, 1337); $result = $this->budgetRepository->searchBudget($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setBudgets($result); $this->collector->setBudgets($result);
} }
@@ -906,7 +904,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-budget_contains': case '-budget_contains':
$result = $this->budgetRepository->searchBudget($value, 1337); $result = $this->budgetRepository->searchBudget($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBudgets($result); $this->collector->excludeBudgets($result);
} }
@@ -917,7 +915,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'budget_is': case 'budget_is':
$budget = $this->budgetRepository->findByName($value); $budget = $this->budgetRepository->findByName($value);
if (null !== $budget) { if (null !== $budget) {
$this->collector->setBudget($budget); $this->collector->setBudget($budget);
@@ -928,7 +926,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-budget_is': case '-budget_is':
$budget = $this->budgetRepository->findByName($value); $budget = $this->budgetRepository->findByName($value);
if (null !== $budget) { if (null !== $budget) {
$this->collector->excludeBudget($budget); $this->collector->excludeBudget($budget);
@@ -939,7 +937,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'budget_ends': case 'budget_ends':
$result = $this->budgetRepository->budgetEndsWith($value, 1337); $result = $this->budgetRepository->budgetEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setBudgets($result); $this->collector->setBudgets($result);
} }
@@ -950,7 +948,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-budget_ends': case '-budget_ends':
$result = $this->budgetRepository->budgetEndsWith($value, 1337); $result = $this->budgetRepository->budgetEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBudgets($result); $this->collector->excludeBudgets($result);
} }
@@ -961,7 +959,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'budget_starts': case 'budget_starts':
$result = $this->budgetRepository->budgetStartsWith($value, 1337); $result = $this->budgetRepository->budgetStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setBudgets($result); $this->collector->setBudgets($result);
} }
@@ -972,7 +970,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-budget_starts': case '-budget_starts':
$result = $this->budgetRepository->budgetStartsWith($value, 1337); $result = $this->budgetRepository->budgetStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBudgets($result); $this->collector->excludeBudgets($result);
} }
@@ -982,9 +980,9 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// bill // bill
// //
case '-has_any_bill': case '-has_any_bill':
case 'has_no_bill': case 'has_no_bill':
$this->collector->withoutBill(); $this->collector->withoutBill();
@@ -998,7 +996,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'bill_contains': case 'bill_contains':
$result = $this->billRepository->searchBill($value, 1337); $result = $this->billRepository->searchBill($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setBills($result); $this->collector->setBills($result);
@@ -1009,7 +1007,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-bill_contains': case '-bill_contains':
$result = $this->billRepository->searchBill($value, 1337); $result = $this->billRepository->searchBill($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBills($result); $this->collector->excludeBills($result);
@@ -1020,7 +1018,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'bill_is': case 'bill_is':
$bill = $this->billRepository->findByName($value); $bill = $this->billRepository->findByName($value);
if (null !== $bill) { if (null !== $bill) {
$this->collector->setBill($bill); $this->collector->setBill($bill);
@@ -1031,7 +1029,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-bill_is': case '-bill_is':
$bill = $this->billRepository->findByName($value); $bill = $this->billRepository->findByName($value);
if (null !== $bill) { if (null !== $bill) {
$this->collector->excludeBills(new Collection([$bill])); $this->collector->excludeBills(new Collection([$bill]));
@@ -1042,7 +1040,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'bill_ends': case 'bill_ends':
$result = $this->billRepository->billEndsWith($value, 1337); $result = $this->billRepository->billEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setBills($result); $this->collector->setBills($result);
} }
@@ -1053,7 +1051,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-bill_ends': case '-bill_ends':
$result = $this->billRepository->billEndsWith($value, 1337); $result = $this->billRepository->billEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBills($result); $this->collector->excludeBills($result);
} }
@@ -1064,7 +1062,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'bill_starts': case 'bill_starts':
$result = $this->billRepository->billStartsWith($value, 1337); $result = $this->billRepository->billStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->setBills($result); $this->collector->setBills($result);
} }
@@ -1075,7 +1073,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-bill_starts': case '-bill_starts':
$result = $this->billRepository->billStartsWith($value, 1337); $result = $this->billRepository->billStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBills($result); $this->collector->excludeBills($result);
} }
@@ -1085,9 +1083,9 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// tags // tags
// //
case '-has_any_tag': case '-has_any_tag':
case 'has_no_tag': case 'has_no_tag':
$this->collector->withoutTags(); $this->collector->withoutTags();
@@ -1102,7 +1100,7 @@ class OperatorQuerySearch implements SearchInterface
case '-tag_is_not': case '-tag_is_not':
case 'tag_is': case 'tag_is':
$result = $this->tagRepository->findByTag($value); $result = $this->tagRepository->findByTag($value);
if (null !== $result) { if (null !== $result) {
$this->includeTags[] = $result->id; $this->includeTags[] = $result->id;
$this->includeTags = array_unique($this->includeTags); $this->includeTags = array_unique($this->includeTags);
@@ -1116,7 +1114,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'tag_contains': case 'tag_contains':
$tags = $this->tagRepository->searchTag($value); $tags = $this->tagRepository->searchTag($value);
if (0 === $tags->count()) { if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator)); app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing(); $this->collector->findNothing();
@@ -1130,7 +1128,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'tag_starts': case 'tag_starts':
$tags = $this->tagRepository->tagStartsWith($value); $tags = $this->tagRepository->tagStartsWith($value);
if (0 === $tags->count()) { if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator)); app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing(); $this->collector->findNothing();
@@ -1144,7 +1142,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-tag_starts': case '-tag_starts':
$tags = $this->tagRepository->tagStartsWith($value); $tags = $this->tagRepository->tagStartsWith($value);
if (0 === $tags->count()) { if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator)); app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing(); $this->collector->findNothing();
@@ -1157,7 +1155,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case 'tag_ends': case 'tag_ends':
$tags = $this->tagRepository->tagEndsWith($value); $tags = $this->tagRepository->tagEndsWith($value);
if (0 === $tags->count()) { if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator)); app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing(); $this->collector->findNothing();
@@ -1170,7 +1168,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-tag_ends': case '-tag_ends':
$tags = $this->tagRepository->tagEndsWith($value); $tags = $this->tagRepository->tagEndsWith($value);
if (0 === $tags->count()) { if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator)); app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
$this->collector->findNothing(); $this->collector->findNothing();
@@ -1183,7 +1181,7 @@ class OperatorQuerySearch implements SearchInterface
break; break;
case '-tag_contains': case '-tag_contains':
$tags = $this->tagRepository->searchTag($value)->keyBy('id'); $tags = $this->tagRepository->searchTag($value)->keyBy('id');
if (0 === $tags->count()) { if (0 === $tags->count()) {
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator)); app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
@@ -1198,7 +1196,7 @@ class OperatorQuerySearch implements SearchInterface
case '-tag_is': case '-tag_is':
case 'tag_is_not': case 'tag_is_not':
$result = $this->tagRepository->findByTag($value); $result = $this->tagRepository->findByTag($value);
if (null !== $result) { if (null !== $result) {
$this->excludeTags[] = $result->id; $this->excludeTags[] = $result->id;
$this->excludeTags = array_unique($this->excludeTags); $this->excludeTags = array_unique($this->excludeTags);
@@ -1206,9 +1204,9 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// notes // notes
// //
case 'notes_contains': case 'notes_contains':
$this->collector->notesContain($value); $this->collector->notesContain($value);
@@ -1271,14 +1269,14 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// amount // amount
// //
case 'amount_is': case 'amount_is':
// strip comma's, make dots. // strip comma's, make dots.
app('log')->debug(sprintf('Original value "%s"', $value)); app('log')->debug(sprintf('Original value "%s"', $value));
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountIs($amount); $this->collector->amountIs($amount);
@@ -1287,8 +1285,8 @@ class OperatorQuerySearch implements SearchInterface
case '-amount_is': case '-amount_is':
// strip comma's, make dots. // strip comma's, make dots.
app('log')->debug(sprintf('Original value "%s"', $value)); app('log')->debug(sprintf('Original value "%s"', $value));
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountIsNot($amount); $this->collector->amountIsNot($amount);
@@ -1296,9 +1294,9 @@ class OperatorQuerySearch implements SearchInterface
case 'foreign_amount_is': case 'foreign_amount_is':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountIs($amount); $this->collector->foreignAmountIs($amount);
@@ -1306,9 +1304,9 @@ class OperatorQuerySearch implements SearchInterface
case '-foreign_amount_is': case '-foreign_amount_is':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountIsNot($amount); $this->collector->foreignAmountIsNot($amount);
@@ -1317,9 +1315,9 @@ class OperatorQuerySearch implements SearchInterface
case '-amount_more': case '-amount_more':
case 'amount_less': case 'amount_less':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountLess($amount); $this->collector->amountLess($amount);
@@ -1328,9 +1326,9 @@ class OperatorQuerySearch implements SearchInterface
case '-foreign_amount_more': case '-foreign_amount_more':
case 'foreign_amount_less': case 'foreign_amount_less':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountLess($amount); $this->collector->foreignAmountLess($amount);
@@ -1340,8 +1338,8 @@ class OperatorQuerySearch implements SearchInterface
case 'amount_more': case 'amount_more':
app('log')->debug(sprintf('Now handling operator "%s"', $operator)); app('log')->debug(sprintf('Now handling operator "%s"', $operator));
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountMore($amount); $this->collector->amountMore($amount);
@@ -1351,16 +1349,16 @@ class OperatorQuerySearch implements SearchInterface
case 'foreign_amount_more': case 'foreign_amount_more':
app('log')->debug(sprintf('Now handling operator "%s"', $operator)); app('log')->debug(sprintf('Now handling operator "%s"', $operator));
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', $value); $value = str_replace(',', '.', $value);
$amount = app('steam')->positive($value); $amount = app('steam')->positive($value);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountMore($amount); $this->collector->foreignAmountMore($amount);
break; break;
// //
// transaction type // transaction type
// //
case 'transaction_type': case 'transaction_type':
$this->collector->setTypes([ucfirst($value)]); $this->collector->setTypes([ucfirst($value)]);
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
@@ -1373,152 +1371,152 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// dates // dates
// //
case '-date_on': case '-date_on':
case 'date_on': case 'date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactDateParams($range, $prohibited); $this->setExactDateParams($range, $prohibited);
return false; return false;
case 'date_before': case 'date_before':
case '-date_after': case '-date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setDateBeforeParams($range); $this->setDateBeforeParams($range);
return false; return false;
case 'date_after': case 'date_after':
case '-date_before': case '-date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setDateAfterParams($range); $this->setDateAfterParams($range);
return false; return false;
case 'interest_date_on': case 'interest_date_on':
case '-interest_date_on': case '-interest_date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('interest_date', $range, $prohibited); $this->setExactMetaDateParams('interest_date', $range, $prohibited);
return false; return false;
case 'interest_date_before': case 'interest_date_before':
case '-interest_date_after': case '-interest_date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('interest_date', $range); $this->setMetaDateBeforeParams('interest_date', $range);
return false; return false;
case 'interest_date_after': case 'interest_date_after':
case '-interest_date_before': case '-interest_date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('interest_date', $range); $this->setMetaDateAfterParams('interest_date', $range);
return false; return false;
case 'book_date_on': case 'book_date_on':
case '-book_date_on': case '-book_date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('book_date', $range, $prohibited); $this->setExactMetaDateParams('book_date', $range, $prohibited);
return false; return false;
case 'book_date_before': case 'book_date_before':
case '-book_date_after': case '-book_date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('book_date', $range); $this->setMetaDateBeforeParams('book_date', $range);
return false; return false;
case 'book_date_after': case 'book_date_after':
case '-book_date_before': case '-book_date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('book_date', $range); $this->setMetaDateAfterParams('book_date', $range);
return false; return false;
case 'process_date_on': case 'process_date_on':
case '-process_date_on': case '-process_date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('process_date', $range, $prohibited); $this->setExactMetaDateParams('process_date', $range, $prohibited);
return false; return false;
case 'process_date_before': case 'process_date_before':
case '-process_date_after': case '-process_date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('process_date', $range); $this->setMetaDateBeforeParams('process_date', $range);
return false; return false;
case 'process_date_after': case 'process_date_after':
case '-process_date_before': case '-process_date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('process_date', $range); $this->setMetaDateAfterParams('process_date', $range);
return false; return false;
case 'due_date_on': case 'due_date_on':
case '-due_date_on': case '-due_date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('due_date', $range, $prohibited); $this->setExactMetaDateParams('due_date', $range, $prohibited);
return false; return false;
case 'due_date_before': case 'due_date_before':
case '-due_date_after': case '-due_date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('due_date', $range); $this->setMetaDateBeforeParams('due_date', $range);
return false; return false;
case 'due_date_after': case 'due_date_after':
case '-due_date_before': case '-due_date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('due_date', $range); $this->setMetaDateAfterParams('due_date', $range);
return false; return false;
case 'payment_date_on': case 'payment_date_on':
case '-payment_date_on': case '-payment_date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('payment_date', $range, $prohibited); $this->setExactMetaDateParams('payment_date', $range, $prohibited);
return false; return false;
case 'payment_date_before': case 'payment_date_before':
case '-payment_date_after': case '-payment_date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('payment_date', $range); $this->setMetaDateBeforeParams('payment_date', $range);
return false; return false;
case 'payment_date_after': case 'payment_date_after':
case '-payment_date_before': case '-payment_date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('payment_date', $range); $this->setMetaDateAfterParams('payment_date', $range);
return false; return false;
case 'invoice_date_on': case 'invoice_date_on':
case '-invoice_date_on': case '-invoice_date_on':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('invoice_date', $range, $prohibited); $this->setExactMetaDateParams('invoice_date', $range, $prohibited);
return false; return false;
case 'invoice_date_before': case 'invoice_date_before':
case '-invoice_date_after': case '-invoice_date_after':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('invoice_date', $range); $this->setMetaDateBeforeParams('invoice_date', $range);
return false; return false;
case 'invoice_date_after': case 'invoice_date_after':
case '-invoice_date_before': case '-invoice_date_before':
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('invoice_date', $range); $this->setMetaDateAfterParams('invoice_date', $range);
return false; return false;
@@ -1526,7 +1524,7 @@ class OperatorQuerySearch implements SearchInterface
case 'created_at_on': case 'created_at_on':
case '-created_at_on': case '-created_at_on':
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactObjectDateParams('created_at', $range, $prohibited); $this->setExactObjectDateParams('created_at', $range, $prohibited);
return false; return false;
@@ -1534,7 +1532,7 @@ class OperatorQuerySearch implements SearchInterface
case 'created_at_before': case 'created_at_before':
case '-created_at_after': case '-created_at_after':
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateBeforeParams('created_at', $range); $this->setObjectDateBeforeParams('created_at', $range);
return false; return false;
@@ -1542,7 +1540,7 @@ class OperatorQuerySearch implements SearchInterface
case 'created_at_after': case 'created_at_after':
case '-created_at_before': case '-created_at_before':
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateAfterParams('created_at', $range); $this->setObjectDateAfterParams('created_at', $range);
return false; return false;
@@ -1550,7 +1548,7 @@ class OperatorQuerySearch implements SearchInterface
case 'updated_at_on': case 'updated_at_on':
case '-updated_at_on': case '-updated_at_on':
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setExactObjectDateParams('updated_at', $range, $prohibited); $this->setExactObjectDateParams('updated_at', $range, $prohibited);
return false; return false;
@@ -1558,7 +1556,7 @@ class OperatorQuerySearch implements SearchInterface
case 'updated_at_before': case 'updated_at_before':
case '-updated_at_after': case '-updated_at_after':
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateBeforeParams('updated_at', $range); $this->setObjectDateBeforeParams('updated_at', $range);
return false; return false;
@@ -1566,14 +1564,14 @@ class OperatorQuerySearch implements SearchInterface
case 'updated_at_after': case 'updated_at_after':
case '-updated_at_before': case '-updated_at_before':
app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); app('log')->debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($operator, $value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateAfterParams('updated_at', $range); $this->setObjectDateAfterParams('updated_at', $range);
return false; return false;
// //
// external URL // external URL
// //
case '-any_external_url': case '-any_external_url':
case 'no_external_url': case 'no_external_url':
$this->collector->withoutExternalUrl(); $this->collector->withoutExternalUrl();
@@ -1638,9 +1636,9 @@ class OperatorQuerySearch implements SearchInterface
break; break;
// //
// other fields // other fields
// //
case 'external_id_is': case 'external_id_is':
$this->collector->setExternalId($value); $this->collector->setExternalId($value);
@@ -1842,7 +1840,7 @@ class OperatorQuerySearch implements SearchInterface
$operator = substr($operator, 1); $operator = substr($operator, 1);
} }
$config = config(sprintf('search.operators.%s', $operator)); $config = config(sprintf('search.operators.%s', $operator));
if (null === $config) { if (null === $config) {
throw new FireflyException(sprintf('No configuration for search operator "%s"', $operator)); throw new FireflyException(sprintf('No configuration for search operator "%s"', $operator));
} }
@@ -1896,7 +1894,7 @@ class OperatorQuerySearch implements SearchInterface
} }
} }
// string position (default): starts with: // string position (default): starts with:
$stringMethod = 'str_starts_with'; $stringMethod = 'str_starts_with';
// string position: ends with: // string position: ends with:
if (StringPosition::ENDS === $stringPosition) { if (StringPosition::ENDS === $stringPosition) {
@@ -1910,7 +1908,7 @@ class OperatorQuerySearch implements SearchInterface
} }
// get accounts: // get accounts:
$accounts = $this->accountRepository->searchAccount($value, $searchTypes, 1337); $accounts = $this->accountRepository->searchAccount($value, $searchTypes, 1337);
if (0 === $accounts->count() && false === $prohibited) { if (0 === $accounts->count() && false === $prohibited) {
app('log')->debug('Found zero accounts, search for non existing account, NO results will be returned.'); app('log')->debug('Found zero accounts, search for non existing account, NO results will be returned.');
$this->collector->findNothing(); $this->collector->findNothing();
@@ -1923,7 +1921,7 @@ class OperatorQuerySearch implements SearchInterface
return; return;
} }
app('log')->debug(sprintf('Found %d accounts, will filter.', $accounts->count())); app('log')->debug(sprintf('Found %d accounts, will filter.', $accounts->count()));
$filtered = $accounts->filter( $filtered = $accounts->filter(
static function (Account $account) use ($value, $stringMethod) { static function (Account $account) use ($value, $stringMethod) {
return $stringMethod(strtolower($account->name), strtolower($value)); return $stringMethod(strtolower($account->name), strtolower($value));
} }
@@ -1978,7 +1976,7 @@ class OperatorQuerySearch implements SearchInterface
} }
// string position (default): starts with: // string position (default): starts with:
$stringMethod = 'str_starts_with'; $stringMethod = 'str_starts_with';
// string position: ends with: // string position: ends with:
if (StringPosition::ENDS === $stringPosition) { if (StringPosition::ENDS === $stringPosition) {
@@ -1992,7 +1990,7 @@ class OperatorQuerySearch implements SearchInterface
} }
// search for accounts: // search for accounts:
$accounts = $this->accountRepository->searchAccountNr($value, $searchTypes, 1337); $accounts = $this->accountRepository->searchAccountNr($value, $searchTypes, 1337);
if (0 === $accounts->count()) { if (0 === $accounts->count()) {
app('log')->debug('Found zero accounts, search for invalid account.'); app('log')->debug('Found zero accounts, search for invalid account.');
$this->collector->findNothing(); $this->collector->findNothing();
@@ -2002,7 +2000,7 @@ class OperatorQuerySearch implements SearchInterface
// if found, do filter // if found, do filter
app('log')->debug(sprintf('Found %d accounts, will filter.', $accounts->count())); app('log')->debug(sprintf('Found %d accounts, will filter.', $accounts->count()));
$filtered = $accounts->filter( $filtered = $accounts->filter(
static function (Account $account) use ($value, $stringMethod) { static function (Account $account) use ($value, $stringMethod) {
// either IBAN or account number // either IBAN or account number
$ibanMatch = $stringMethod(strtolower((string) $account->iban), strtolower($value)); $ibanMatch = $stringMethod(strtolower((string) $account->iban), strtolower($value));

View File

@@ -24,18 +24,12 @@ declare(strict_types=1);
namespace FireflyIII\Support; namespace FireflyIII\Support;
use Carbon\Carbon; use Carbon\Carbon;
use DB;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use stdClass;
use Str;
use ValueError;
/** /**
* Class Steam. * Class Steam.
@@ -44,8 +38,8 @@ class Steam
{ {
public function getAccountCurrency(Account $account): ?TransactionCurrency public function getAccountCurrency(Account $account): ?TransactionCurrency
{ {
$type = $account->accountType->type; $type = $account->accountType->type;
$list = config('firefly.valid_currency_account_types'); $list = config('firefly.valid_currency_account_types');
// return null if not in this list. // return null if not in this list.
if (!in_array($type, $list, true)) { if (!in_array($type, $list, true)) {
@@ -55,6 +49,7 @@ class Steam
if (null === $result) { if (null === $result) {
return null; return null;
} }
return TransactionCurrency::find((int) $result->data); return TransactionCurrency::find((int) $result->data);
} }
@@ -72,7 +67,6 @@ class Steam
return $sum; return $sum;
} }
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end): array public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end): array
{ {
// expand period. // expand period.
@@ -80,7 +74,7 @@ class Steam
$end->addDay()->endOfDay(); $end->addDay()->endOfDay();
// set up cache // set up cache
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty('final-balance-in-range'); $cache->addProperty('final-balance-in-range');
$cache->addProperty($start); $cache->addProperty($start);
@@ -89,51 +83,52 @@ class Steam
// return $cache->get(); // return $cache->get();
} }
$balances = []; $balances = [];
$formatted = $start->format('Y-m-d'); $formatted = $start->format('Y-m-d');
$startBalance = $this->finalAccountBalance($account, $start); $startBalance = $this->finalAccountBalance($account, $start);
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = $this->getAccountCurrency($account) ?? $defaultCurrency; $currency = $this->getAccountCurrency($account) ?? $defaultCurrency;
$currencies = [ $currencies = [
$currency->id => $currency, $currency->id => $currency,
$defaultCurrency->id => $defaultCurrency, $defaultCurrency->id => $defaultCurrency,
]; ];
$startBalance[$defaultCurrency->code] ??= '0'; $startBalance[$defaultCurrency->code] ??= '0';
$startBalance[$currency->code] ??= '0'; $startBalance[$currency->code] ??= '0';
$balances[$formatted] = $startBalance; $balances[$formatted] = $startBalance;
// sums up the balance changes per day, for foreign, native and normal amounts. // sums up the balance changes per day, for foreign, native and normal amounts.
$set = $account->transactions() $set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
->groupBy('transaction_journals.date') ->groupBy('transaction_journals.date')
->groupBy('transactions.transaction_currency_id') ->groupBy('transactions.transaction_currency_id')
->groupBy('transactions.foreign_currency_id') ->groupBy('transactions.foreign_currency_id')
->orderBy('transaction_journals.date', 'ASC') ->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->get( ->get(
[ // @phpstan-ignore-line [ // @phpstan-ignore-line
'transaction_journals.date', 'transaction_journals.date',
'transactions.transaction_currency_id', 'transactions.transaction_currency_id',
DB::raw('SUM(transactions.amount) AS modified'), \DB::raw('SUM(transactions.amount) AS modified'),
'transactions.foreign_currency_id', 'transactions.foreign_currency_id',
DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'), \DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
DB::raw('SUM(transactions.native_amount) AS modified_native'), \DB::raw('SUM(transactions.native_amount) AS modified_native'),
] ]
); )
;
$currentBalance = $startBalance; $currentBalance = $startBalance;
/** @var Transaction $entry */ /** @var Transaction $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
// normal, native and foreign amount // normal, native and foreign amount
$carbon = new Carbon($entry->date, $entry->date_tz); $carbon = new Carbon($entry->date, $entry->date_tz);
$modified = (string) (null === $entry->modified ? '0' : $entry->modified); $modified = (string) (null === $entry->modified ? '0' : $entry->modified);
$foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign); $foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign);
$nativeModified = (string) (null === $entry->modified_native ? '0' : $entry->modified_native); $nativeModified = (string) (null === $entry->modified_native ? '0' : $entry->modified_native);
// add "modified" to amount if the currency id matches the account currency id. // add "modified" to amount if the currency id matches the account currency id.
if ($entry->transaction_currency_id === $currency->id) { if ($entry->transaction_currency_id === $currency->id) {
@@ -142,7 +137,7 @@ class Steam
} }
// always add the native balance, even if it ends up at zero. // always add the native balance, even if it ends up at zero.
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeModified); $currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeModified);
// add modified foreign to the array // add modified foreign to the array
if (null !== $entry->foreign_currency_id) { if (null !== $entry->foreign_currency_id) {
@@ -159,11 +154,13 @@ class Steam
return $balances; return $balances;
} }
public function finalAccountsBalance(Collection $accounts, Carbon $date): array { public function finalAccountsBalance(Collection $accounts, Carbon $date): array
{
$balances = []; $balances = [];
foreach ($accounts as $account) { foreach ($accounts as $account) {
$balances[$account->id] = $this->finalAccountBalance($account, $date); $balances[$account->id] = $this->finalAccountBalance($account, $date);
} }
return $balances; return $balances;
} }
@@ -186,10 +183,10 @@ class Steam
// Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision)); // Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
if (str_contains($number, '.')) { if (str_contains($number, '.')) {
if ('-' !== $number[0]) { if ('-' !== $number[0]) {
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision); return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision);
} }
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision); return bcsub($number, '0.'.str_repeat('0', $precision).'5', $precision);
} }
return $number; return $number;
@@ -261,26 +258,22 @@ class Steam
* THAT currency. * THAT currency.
* "native_balance" the balance according to the "native_amount" + "native_foreign_amount" fields. * "native_balance" the balance according to the "native_amount" + "native_foreign_amount" fields.
* "ABC" the balance in this particular currency code (may repeat for each found currency). * "ABC" the balance in this particular currency code (may repeat for each found currency).
*
* @param Account $account
* @param Carbon $date
*
* @return array
*/ */
public function finalAccountBalance(Account $account, Carbon $date): array public function finalAccountBalance(Account $account, Carbon $date): array
{ {
$native = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); $native = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = $this->getAccountCurrency($account) ?? $native; $currency = $this->getAccountCurrency($account) ?? $native;
$return = [ $return = [
'native_balance' => '0', 'native_balance' => '0',
]; ];
Log::debug(sprintf('Now in finalAccountBalance("%s", "%s")', $account->name, $date->format('Y-m-d H:i:s'))); Log::debug(sprintf('Now in finalAccountBalance("%s", "%s")', $account->name, $date->format('Y-m-d H:i:s')));
// first, the "balance", as described earlier. // first, the "balance", as described earlier.
$array = $account->transactions() $array = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->where('transactions.transaction_currency_id', $currency->id) ->where('transactions.transaction_currency_id', $currency->id)
->get(['transactions.amount'])->toArray(); ->get(['transactions.amount'])->toArray()
;
$return['balance'] = $this->sumTransactions($array, 'amount'); $return['balance'] = $this->sumTransactions($array, 'amount');
Log::debug(sprintf('balance is %s', $return['balance'])); Log::debug(sprintf('balance is %s', $return['balance']));
// add virtual balance: // add virtual balance:
@@ -290,9 +283,10 @@ class Steam
// then, native balance (if necessary( // then, native balance (if necessary(
if ($native->id !== $currency->id) { if ($native->id !== $currency->id) {
$array = $account->transactions() $array = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->get(['transactions.native_amount'])->toArray(); ->get(['transactions.native_amount'])->toArray()
;
$return['native_balance'] = $this->sumTransactions($array, 'native_amount'); $return['native_balance'] = $this->sumTransactions($array, 'native_amount');
Log::debug(sprintf('native_balance is %s', $return['native_balance'])); Log::debug(sprintf('native_balance is %s', $return['native_balance']));
$return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['balance']); $return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['balance']);
@@ -300,13 +294,15 @@ class Steam
} }
// balance(s) in other currencies. // balance(s) in other currencies.
$array = $account->transactions() $array = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id') ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->get(['transaction_currencies.code', 'transactions.amount'])->toArray(); ->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
$others = $this->groupAndSumTransactions($array, 'code', 'amount'); ;
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
Log::debug('All others are (joined)', $others); Log::debug('All others are (joined)', $others);
return array_merge($return, $others); return array_merge($return, $others);
} }
@@ -318,6 +314,7 @@ class Steam
$groupKey = $item[$group] ?? 'unknown'; $groupKey = $item[$group] ?? 'unknown';
$return[$groupKey] = bcadd($return[$groupKey] ?? '0', $item[$field]); $return[$groupKey] = bcadd($return[$groupKey] ?? '0', $item[$field]);
} }
return $return; return $return;
} }
@@ -330,7 +327,7 @@ class Steam
try { try {
$hostName = gethostbyaddr($ipAddress); $hostName = gethostbyaddr($ipAddress);
} catch (Exception $e) { } catch (\Exception $e) {
app('log')->error($e->getMessage()); app('log')->error($e->getMessage());
$hostName = $ipAddress; $hostName = $ipAddress;
} }
@@ -346,15 +343,15 @@ class Steam
{ {
$list = []; $list = [];
$set = auth()->user()->transactions() $set = auth()->user()->transactions()
->whereIn('transactions.account_id', $accounts) ->whereIn('transactions.account_id', $accounts)
->groupBy(['transactions.account_id', 'transaction_journals.user_id']) ->groupBy(['transactions.account_id', 'transaction_journals.user_id'])
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line ->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line
; ;
/** @var Transaction $entry */ /** @var Transaction $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$date = new Carbon($entry->max_date, config('app.timezone')); $date = new Carbon($entry->max_date, config('app.timezone'));
$date->setTimezone(config('app.timezone')); $date->setTimezone(config('app.timezone'));
$list[$entry->account_id] = $date; $list[$entry->account_id] = $date;
} }
@@ -429,9 +426,9 @@ class Steam
public function getSafeUrl(string $unknownUrl, string $safeUrl): string public function getSafeUrl(string $unknownUrl, string $safeUrl): string
{ {
// Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl)); // Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
$returnUrl = $safeUrl; $returnUrl = $safeUrl;
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST); $unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
$safeHost = parse_url($safeUrl, PHP_URL_HOST); $safeHost = parse_url($safeUrl, PHP_URL_HOST);
if (null !== $unknownHost && $unknownHost === $safeHost) { if (null !== $unknownHost && $unknownHost === $safeHost) {
$returnUrl = $unknownUrl; $returnUrl = $unknownUrl;
@@ -439,7 +436,7 @@ class Steam
// URL must not lead to weird pages // URL must not lead to weird pages
$forbiddenWords = ['jscript', 'json', 'debug', 'serviceworker', 'offline', 'delete', '/login', '/attachments/view']; $forbiddenWords = ['jscript', 'json', 'debug', 'serviceworker', 'offline', 'delete', '/login', '/attachments/view'];
if (Str::contains($returnUrl, $forbiddenWords)) { if (\Str::contains($returnUrl, $forbiddenWords)) {
$returnUrl = $safeUrl; $returnUrl = $safeUrl;
} }
@@ -468,7 +465,7 @@ class Steam
*/ */
public function floatalize(string $value): string public function floatalize(string $value): string
{ {
$value = strtoupper($value); $value = strtoupper($value);
if (!str_contains($value, 'E')) { if (!str_contains($value, 'E')) {
return $value; return $value;
} }
@@ -537,7 +534,7 @@ class Steam
if (-1 === bccomp($amount, '0')) { if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1'); $amount = bcmul($amount, '-1');
} }
} catch (ValueError $e) { } catch (\ValueError $e) {
Log::error(sprintf('ValueError in Steam::positive("%s"): %s', $amount, $e->getMessage())); Log::error(sprintf('ValueError in Steam::positive("%s"): %s', $amount, $e->getMessage()));
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());

View File

@@ -24,8 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\System; namespace FireflyIII\Support\System;
use Artisan;
use Crypt;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\DecryptException;
use Laravel\Passport\Console\KeysCommand; use Laravel\Passport\Console\KeysCommand;
@@ -67,7 +65,7 @@ class OAuthKeys
try { try {
$privateKey = (string) app('fireflyconfig')->get(self::PRIVATE_KEY)?->data; $privateKey = (string) app('fireflyconfig')->get(self::PRIVATE_KEY)?->data;
$publicKey = (string) app('fireflyconfig')->get(self::PUBLIC_KEY)?->data; $publicKey = (string) app('fireflyconfig')->get(self::PUBLIC_KEY)?->data;
} catch (ContainerExceptionInterface | FireflyException | NotFoundExceptionInterface $e) { } catch (ContainerExceptionInterface|FireflyException|NotFoundExceptionInterface $e) {
app('log')->error(sprintf('Could not validate keysInDatabase(): %s', $e->getMessage())); app('log')->error(sprintf('Could not validate keysInDatabase(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString()); app('log')->error($e->getTraceAsString());
} }
@@ -89,16 +87,16 @@ class OAuthKeys
public static function generateKeys(): void public static function generateKeys(): void
{ {
Artisan::registerCommand(new KeysCommand()); \Artisan::registerCommand(new KeysCommand());
Artisan::call('firefly-iii:laravel-passport-keys'); \Artisan::call('firefly-iii:laravel-passport-keys');
} }
public static function storeKeysInDB(): void public static function storeKeysInDB(): void
{ {
$private = storage_path('oauth-private.key'); $private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key'); $public = storage_path('oauth-public.key');
app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private))); app('fireflyconfig')->set(self::PRIVATE_KEY, \Crypt::encrypt(file_get_contents($private)));
app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public))); app('fireflyconfig')->set(self::PUBLIC_KEY, \Crypt::encrypt(file_get_contents($public)));
} }
/** /**
@@ -110,8 +108,8 @@ class OAuthKeys
$publicKey = (string) app('fireflyconfig')->get(self::PUBLIC_KEY)?->data; $publicKey = (string) app('fireflyconfig')->get(self::PUBLIC_KEY)?->data;
try { try {
$privateContent = Crypt::decrypt($privateKey); $privateContent = \Crypt::decrypt($privateKey);
$publicContent = Crypt::decrypt($publicKey); $publicContent = \Crypt::decrypt($publicKey);
} catch (DecryptException $e) { } catch (DecryptException $e) {
app('log')->error('Could not decrypt pub/private keypair.'); app('log')->error('Could not decrypt pub/private keypair.');
app('log')->error($e->getMessage()); app('log')->error($e->getMessage());
@@ -122,8 +120,8 @@ class OAuthKeys
return false; return false;
} }
$private = storage_path('oauth-private.key'); $private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key'); $public = storage_path('oauth-public.key');
file_put_contents($private, $privateContent); file_put_contents($private, $privateContent);
file_put_contents($public, $publicContent); file_put_contents($public, $publicContent);

View File

@@ -108,8 +108,8 @@ class AmountFormat extends AbstractExtension
return new TwigFunction( return new TwigFunction(
'formatAmountBySymbol', 'formatAmountBySymbol',
static function (string $amount, string $symbol, ?int $decimalPlaces = null, ?bool $coloured = null): string { static function (string $amount, string $symbol, ?int $decimalPlaces = null, ?bool $coloured = null): string {
$decimalPlaces ??= 2; $decimalPlaces ??= 2;
$coloured ??= true; $coloured ??= true;
$currency = new TransactionCurrency(); $currency = new TransactionCurrency();
$currency->symbol = $symbol; $currency->symbol = $symbol;
$currency->decimal_places = $decimalPlaces; $currency->decimal_places = $decimalPlaces;

View File

@@ -78,6 +78,7 @@ class General extends AbstractExtension
if (!$convertToNative || $currency->code === $native->code) { if (!$convertToNative || $currency->code === $native->code) {
$strings[] = app('amount')->formatAnything($currency, $balance, false); $strings[] = app('amount')->formatAnything($currency, $balance, false);
} }
continue; continue;
} }
if ('native_balance' === $key) { if ('native_balance' === $key) {
@@ -85,6 +86,7 @@ class General extends AbstractExtension
if ($convertToNative) { if ($convertToNative) {
$strings[] = app('amount')->formatAnything($native, $balance, false); $strings[] = app('amount')->formatAnything($native, $balance, false);
} }
continue; continue;
} }
if ($key !== $currency->code) { if ($key !== $currency->code) {
@@ -108,15 +110,15 @@ class General extends AbstractExtension
static function (int $size): string { static function (int $size): string {
// less than one GB, more than one MB // less than one GB, more than one MB
if ($size < (1024 * 1024 * 2014) && $size >= (1024 * 1024)) { if ($size < (1024 * 1024 * 2014) && $size >= (1024 * 1024)) {
return round($size / (1024 * 1024), 2) . ' MB'; return round($size / (1024 * 1024), 2).' MB';
} }
// less than one MB // less than one MB
if ($size < (1024 * 1024)) { if ($size < (1024 * 1024)) {
return round($size / 1024, 2) . ' KB'; return round($size / 1024, 2).' KB';
} }
return $size . ' bytes'; return $size.' bytes';
} }
); );
} }
@@ -138,7 +140,7 @@ class General extends AbstractExtension
case 'application/pdf': case 'application/pdf':
return 'fa-file-pdf-o'; return 'fa-file-pdf-o';
// image // image
case 'image/png': case 'image/png':
case 'image/jpeg': case 'image/jpeg':
case 'image/svg+xml': case 'image/svg+xml':
@@ -147,7 +149,7 @@ class General extends AbstractExtension
case 'application/vnd.oasis.opendocument.image': case 'application/vnd.oasis.opendocument.image':
return 'fa-file-image-o'; return 'fa-file-image-o';
// MS word // MS word
case 'application/msword': case 'application/msword':
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': case 'application/vnd.openxmlformats-officedocument.wordprocessingml.template':
@@ -163,7 +165,7 @@ class General extends AbstractExtension
case 'application/vnd.oasis.opendocument.text-master': case 'application/vnd.oasis.opendocument.text-master':
return 'fa-file-word-o'; return 'fa-file-word-o';
// MS excel // MS excel
case 'application/vnd.ms-excel': case 'application/vnd.ms-excel':
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.template': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.template':
@@ -174,7 +176,7 @@ class General extends AbstractExtension
case 'application/vnd.oasis.opendocument.spreadsheet-template': case 'application/vnd.oasis.opendocument.spreadsheet-template':
return 'fa-file-excel-o'; return 'fa-file-excel-o';
// MS powerpoint // MS powerpoint
case 'application/vnd.ms-powerpoint': case 'application/vnd.ms-powerpoint':
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation': case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
case 'application/vnd.openxmlformats-officedocument.presentationml.template': case 'application/vnd.openxmlformats-officedocument.presentationml.template':
@@ -186,7 +188,7 @@ class General extends AbstractExtension
case 'application/vnd.oasis.opendocument.presentation-template': case 'application/vnd.oasis.opendocument.presentation-template':
return 'fa-file-powerpoint-o'; return 'fa-file-powerpoint-o';
// calc // calc
case 'application/vnd.sun.xml.draw': case 'application/vnd.sun.xml.draw':
case 'application/vnd.sun.xml.draw.template': case 'application/vnd.sun.xml.draw.template':
case 'application/vnd.stardivision.draw': case 'application/vnd.stardivision.draw':
@@ -282,7 +284,7 @@ class General extends AbstractExtension
$args = func_get_args(); $args = func_get_args();
$route = $args[0]; // name of the route. $route = $args[0]; // name of the route.
if (Route::getCurrentRoute()->getName() === $route) { if (\Route::getCurrentRoute()->getName() === $route) {
return 'active'; return 'active';
} }
@@ -302,7 +304,7 @@ class General extends AbstractExtension
static function (): string { static function (): string {
$args = func_get_args(); $args = func_get_args();
$route = $args[0]; // name of the route. $route = $args[0]; // name of the route.
$name = Route::getCurrentRoute()->getName() ?? ''; $name = \Route::getCurrentRoute()->getName() ?? '';
if (str_contains($name, $route)) { if (str_contains($name, $route)) {
return 'active'; return 'active';
} }
@@ -322,11 +324,11 @@ class General extends AbstractExtension
'activeRoutePartialObjectType', 'activeRoutePartialObjectType',
static function ($context): string { static function ($context): string {
[, $route, $objectType] = func_get_args(); [, $route, $objectType] = func_get_args();
$activeObjectType = $context['objectType'] ?? false; $activeObjectType = $context['objectType'] ?? false;
if ($objectType === $activeObjectType if ($objectType === $activeObjectType
&& false !== stripos( && false !== stripos(
Route::getCurrentRoute()->getName(), \Route::getCurrentRoute()->getName(),
$route $route
)) { )) {
return 'active'; return 'active';
@@ -349,7 +351,7 @@ class General extends AbstractExtension
static function (): string { static function (): string {
$args = func_get_args(); $args = func_get_args();
$route = $args[0]; // name of the route. $route = $args[0]; // name of the route.
$name = Route::getCurrentRoute()->getName() ?? ''; $name = \Route::getCurrentRoute()->getName() ?? '';
if (str_contains($name, $route)) { if (str_contains($name, $route)) {
return 'menu-open'; return 'menu-open';
} }

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\Twig; namespace FireflyIII\Support\Twig;
use Config;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFunction; use Twig\TwigFunction;
@@ -64,7 +63,7 @@ class Rule extends AbstractExtension
$possibleTriggers = []; $possibleTriggers = [];
foreach ($ruleTriggers as $key) { foreach ($ruleTriggers as $key) {
if ('user_action' !== $key) { if ('user_action' !== $key) {
$possibleTriggers[$key] = (string) trans('firefly.rule_trigger_' . $key . '_choice'); $possibleTriggers[$key] = (string) trans('firefly.rule_trigger_'.$key.'_choice');
} }
} }
unset($ruleTriggers); unset($ruleTriggers);
@@ -81,10 +80,10 @@ class Rule extends AbstractExtension
'allRuleActions', 'allRuleActions',
static function () { static function () {
// array of valid values for actions // array of valid values for actions
$ruleActions = array_keys(Config::get('firefly.rule-actions')); $ruleActions = array_keys(\Config::get('firefly.rule-actions'));
$possibleActions = []; $possibleActions = [];
foreach ($ruleActions as $key) { foreach ($ruleActions as $key) {
$possibleActions[$key] = (string) trans('firefly.rule_action_' . $key . '_choice'); $possibleActions[$key] = (string) trans('firefly.rule_action_'.$key.'_choice');
} }
unset($ruleActions); unset($ruleActions);
asort($possibleActions); asort($possibleActions);

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\Twig; namespace FireflyIII\Support\Twig;
use Carbon\Carbon; use Carbon\Carbon;
use DB;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -87,7 +86,7 @@ class TransactionGroupTwig extends AbstractExtension
$colored = false; $colored = false;
} }
$result = app('amount')->formatFlat($array['currency_symbol'], (int) $array['currency_decimal_places'], $amount, $colored); $result = app('amount')->formatFlat($array['currency_symbol'], (int) $array['currency_decimal_places'], $amount, $colored);
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$result = sprintf('<span class="text-info money-transfer">%s</span>', $result); $result = sprintf('<span class="text-info money-transfer">%s</span>', $result);
} }
@@ -120,9 +119,9 @@ class TransactionGroupTwig extends AbstractExtension
*/ */
private function foreignJournalArrayAmount(array $array): string private function foreignJournalArrayAmount(array $array): string
{ {
$type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL; $type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['foreign_amount'] ?? '0'; $amount = $array['foreign_amount'] ?? '0';
$colored = true; $colored = true;
$sourceType = $array['source_account_type'] ?? 'invalid'; $sourceType = $array['source_account_type'] ?? 'invalid';
$amount = $this->signAmount($amount, $type, $sourceType); $amount = $this->signAmount($amount, $type, $sourceType);
@@ -130,7 +129,7 @@ class TransactionGroupTwig extends AbstractExtension
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$colored = false; $colored = false;
} }
$result = app('amount')->formatFlat($array['foreign_currency_symbol'], (int) $array['foreign_currency_decimal_places'], $amount, $colored); $result = app('amount')->formatFlat($array['foreign_currency_symbol'], (int) $array['foreign_currency_decimal_places'], $amount, $colored);
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$result = sprintf('<span class="text-info money-transfer">%s</span>', $result); $result = sprintf('<span class="text-info money-transfer">%s</span>', $result);
} }
@@ -171,12 +170,12 @@ class TransactionGroupTwig extends AbstractExtension
$colored = true; $colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type; $sourceType = $first->account()->first()->accountType()->first()->type;
$amount = $this->signAmount($amount, $type, $sourceType); $amount = $this->signAmount($amount, $type, $sourceType);
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$colored = false; $colored = false;
} }
$result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored); $result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored);
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$result = sprintf('<span class="text-info money-transfer">%s</span>', $result); $result = sprintf('<span class="text-info money-transfer">%s</span>', $result);
} }
@@ -197,7 +196,7 @@ class TransactionGroupTwig extends AbstractExtension
*/ */
private function foreignJournalObjectAmount(TransactionJournal $journal): string private function foreignJournalObjectAmount(TransactionJournal $journal): string
{ {
$type = $journal->transactionType->type; $type = $journal->transactionType->type;
/** @var Transaction $first */ /** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first(); $first = $journal->transactions()->where('amount', '<', 0)->first();
@@ -206,12 +205,12 @@ class TransactionGroupTwig extends AbstractExtension
$colored = true; $colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type; $sourceType = $first->account()->first()->accountType()->first()->type;
$amount = $this->signAmount($amount, $type, $sourceType); $amount = $this->signAmount($amount, $type, $sourceType);
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$colored = false; $colored = false;
} }
$result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored); $result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored);
if (TransactionType::TRANSFER === $type) { if (TransactionType::TRANSFER === $type) {
$result = sprintf('<span class="text-info money-transfer">%s</span>', $result); $result = sprintf('<span class="text-info money-transfer">%s</span>', $result);
} }
@@ -224,11 +223,12 @@ class TransactionGroupTwig extends AbstractExtension
return new TwigFunction( return new TwigFunction(
'journalHasMeta', 'journalHasMeta',
static function (int $journalId, string $metaField) { static function (int $journalId, string $metaField) {
$count = DB::table('journal_meta') $count = \DB::table('journal_meta')
->where('name', $metaField) ->where('name', $metaField)
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereNull('deleted_at') ->whereNull('deleted_at')
->count(); ->count()
;
return 1 === $count; return 1 === $count;
} }
@@ -241,11 +241,12 @@ class TransactionGroupTwig extends AbstractExtension
'journalGetMetaDate', 'journalGetMetaDate',
static function (int $journalId, string $metaField) { static function (int $journalId, string $metaField) {
/** @var null|TransactionJournalMeta $entry */ /** @var null|TransactionJournalMeta $entry */
$entry = DB::table('journal_meta') $entry = \DB::table('journal_meta')
->where('name', $metaField) ->where('name', $metaField)
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereNull('deleted_at') ->whereNull('deleted_at')
->first(); ->first()
;
if (null === $entry) { if (null === $entry) {
return today(config('app.timezone')); return today(config('app.timezone'));
} }
@@ -261,11 +262,12 @@ class TransactionGroupTwig extends AbstractExtension
'journalGetMetaField', 'journalGetMetaField',
static function (int $journalId, string $metaField) { static function (int $journalId, string $metaField) {
/** @var null|TransactionJournalMeta $entry */ /** @var null|TransactionJournalMeta $entry */
$entry = DB::table('journal_meta') $entry = \DB::table('journal_meta')
->where('name', $metaField) ->where('name', $metaField)
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereNull('deleted_at') ->whereNull('deleted_at')
->first(); ->first()
;
if (null === $entry) { if (null === $entry) {
return ''; return '';
} }

View File

@@ -14,17 +14,14 @@
"/public/v1/js/app.js.LICENSE.txt": "/public/v1/js/app.js.LICENSE.txt", "/public/v1/js/app.js.LICENSE.txt": "/public/v1/js/app.js.LICENSE.txt",
"/public/v1/js/app_vue.js": "/public/v1/js/app_vue.js", "/public/v1/js/app_vue.js": "/public/v1/js/app_vue.js",
"/public/v1/js/app_vue.js.LICENSE.txt": "/public/v1/js/app_vue.js.LICENSE.txt", "/public/v1/js/app_vue.js.LICENSE.txt": "/public/v1/js/app_vue.js.LICENSE.txt",
"/public/v1/js/create.js": "/public/v1/js/create.js",
"/public/v1/js/create.js.LICENSE.txt": "/public/v1/js/create.js.LICENSE.txt",
"/public/v1/js/create_transaction.js": "/public/v1/js/create_transaction.js", "/public/v1/js/create_transaction.js": "/public/v1/js/create_transaction.js",
"/public/v1/js/create_transaction.js.LICENSE.txt": "/public/v1/js/create_transaction.js.LICENSE.txt", "/public/v1/js/create_transaction.js.LICENSE.txt": "/public/v1/js/create_transaction.js.LICENSE.txt",
"/public/v1/js/edit.js": "/public/v1/js/edit.js",
"/public/v1/js/edit.js.LICENSE.txt": "/public/v1/js/edit.js.LICENSE.txt",
"/public/v1/js/edit_transaction.js": "/public/v1/js/edit_transaction.js", "/public/v1/js/edit_transaction.js": "/public/v1/js/edit_transaction.js",
"/public/v1/js/edit_transaction.js.LICENSE.txt": "/public/v1/js/edit_transaction.js.LICENSE.txt", "/public/v1/js/edit_transaction.js.LICENSE.txt": "/public/v1/js/edit_transaction.js.LICENSE.txt",
"/public/v1/js/exchange-rates/index.js": "/public/v1/js/exchange-rates/index.js", "/public/v1/js/exchange-rates/index.js": "/public/v1/js/exchange-rates/index.js",
"/public/v1/js/exchange-rates/index.js.LICENSE.txt": "/public/v1/js/exchange-rates/index.js.LICENSE.txt", "/public/v1/js/exchange-rates/index.js.LICENSE.txt": "/public/v1/js/exchange-rates/index.js.LICENSE.txt",
"/public/v1/js/exchange-rates/rates.js": "/public/v1/js/exchange-rates/rates.js", "/public/v1/js/exchange-rates/rates.js": "/public/v1/js/exchange-rates/rates.js",
"/public/v1/js/exchange-rates/rates.js.LICENSE.txt": "/public/v1/js/exchange-rates/rates.js.LICENSE.txt",
"/public/v1/js/ff/accounts/create.js": "/public/v1/js/ff/accounts/create.js", "/public/v1/js/ff/accounts/create.js": "/public/v1/js/ff/accounts/create.js",
"/public/v1/js/ff/accounts/edit-reconciliation.js": "/public/v1/js/ff/accounts/edit-reconciliation.js", "/public/v1/js/ff/accounts/edit-reconciliation.js": "/public/v1/js/ff/accounts/edit-reconciliation.js",
"/public/v1/js/ff/accounts/edit.js": "/public/v1/js/ff/accounts/edit.js", "/public/v1/js/ff/accounts/edit.js": "/public/v1/js/ff/accounts/edit.js",
@@ -93,8 +90,6 @@
"/public/v1/js/ff/transactions/mass/edit-bulk.js": "/public/v1/js/ff/transactions/mass/edit-bulk.js", "/public/v1/js/ff/transactions/mass/edit-bulk.js": "/public/v1/js/ff/transactions/mass/edit-bulk.js",
"/public/v1/js/ff/transactions/mass/edit.js": "/public/v1/js/ff/transactions/mass/edit.js", "/public/v1/js/ff/transactions/mass/edit.js": "/public/v1/js/ff/transactions/mass/edit.js",
"/public/v1/js/ff/transactions/show.js": "/public/v1/js/ff/transactions/show.js", "/public/v1/js/ff/transactions/show.js": "/public/v1/js/ff/transactions/show.js",
"/public/v1/js/index.js": "/public/v1/js/index.js",
"/public/v1/js/index.js.LICENSE.txt": "/public/v1/js/index.js.LICENSE.txt",
"/public/v1/js/lib/Chart.bundle.min.js": "/public/v1/js/lib/Chart.bundle.min.js", "/public/v1/js/lib/Chart.bundle.min.js": "/public/v1/js/lib/Chart.bundle.min.js",
"/public/v1/js/lib/accounting.min.js": "/public/v1/js/lib/accounting.min.js", "/public/v1/js/lib/accounting.min.js": "/public/v1/js/lib/accounting.min.js",
"/public/v1/js/lib/bootstrap-multiselect.js": "/public/v1/js/lib/bootstrap-multiselect.js", "/public/v1/js/lib/bootstrap-multiselect.js": "/public/v1/js/lib/bootstrap-multiselect.js",
@@ -153,8 +148,6 @@
"/public/v1/js/lib/vue.js": "/public/v1/js/lib/vue.js", "/public/v1/js/lib/vue.js": "/public/v1/js/lib/vue.js",
"/public/v1/js/profile.js": "/public/v1/js/profile.js", "/public/v1/js/profile.js": "/public/v1/js/profile.js",
"/public/v1/js/profile.js.LICENSE.txt": "/public/v1/js/profile.js.LICENSE.txt", "/public/v1/js/profile.js.LICENSE.txt": "/public/v1/js/profile.js.LICENSE.txt",
"/public/v1/js/show.js": "/public/v1/js/show.js",
"/public/v1/js/show.js.LICENSE.txt": "/public/v1/js/show.js.LICENSE.txt",
"/public/v1/js/webhooks/create.js": "/public/v1/js/webhooks/create.js", "/public/v1/js/webhooks/create.js": "/public/v1/js/webhooks/create.js",
"/public/v1/js/webhooks/create.js.LICENSE.txt": "/public/v1/js/webhooks/create.js.LICENSE.txt", "/public/v1/js/webhooks/create.js.LICENSE.txt": "/public/v1/js/webhooks/create.js.LICENSE.txt",
"/public/v1/js/webhooks/edit.js": "/public/v1/js/webhooks/edit.js", "/public/v1/js/webhooks/edit.js": "/public/v1/js/webhooks/edit.js",

View File

@@ -136,9 +136,9 @@
"exchange_rates_intro_rates": "Firefly III bla bla bla exchange rates. Inverse is automatically calculated if not provided. Will go back to last found rate.", "exchange_rates_intro_rates": "Firefly III bla bla bla exchange rates. Inverse is automatically calculated if not provided. Will go back to last found rate.",
"header_exchange_rates_rates": "Wechselkurse", "header_exchange_rates_rates": "Wechselkurse",
"header_exchange_rates_table": "Tabelle mit Wechselkursen", "header_exchange_rates_table": "Tabelle mit Wechselkursen",
"help_rate_form": "On this day, how many {to} will you get for one {from}?", "help_rate_form": "An diesem Tag, wie viele {to} werden Sie f\u00fcr einen {from} bekommen?",
"add_new_rate": "Add a new exchange rate", "add_new_rate": "Neuen Wechselkurs hinzuf\u00fcgen",
"save_new_rate": "Save new rate" "save_new_rate": "Neuen Kurs speichern"
}, },
"form": { "form": {
"url": "URL", "url": "URL",
@@ -158,7 +158,7 @@
"webhook_delivery": "Zustellung", "webhook_delivery": "Zustellung",
"from_currency_to_currency": "{from} &rarr; {to}", "from_currency_to_currency": "{from} &rarr; {to}",
"to_currency_from_currency": "{to} &rarr; {from}", "to_currency_from_currency": "{to} &rarr; {from}",
"rate": "Rate" "rate": "Kurs"
}, },
"list": { "list": {
"active": "Aktiv?", "active": "Aktiv?",

View File

@@ -130,15 +130,15 @@
"response": "Odpowied\u017a", "response": "Odpowied\u017a",
"visit_webhook_url": "Odwied\u017a adres URL webhooka", "visit_webhook_url": "Odwied\u017a adres URL webhooka",
"reset_webhook_secret": "Resetuj sekret webhooka", "reset_webhook_secret": "Resetuj sekret webhooka",
"header_exchange_rates": "Exchange rates", "header_exchange_rates": "Kursy wymiany",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.", "exchange_rates_intro": "Firefly III obs\u0142uguje pobieranie i korzystanie z kurs\u00f3w wymiany walut. Wi\u0119cej informacji na ten temat w <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">dokumentacji<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)", "exchange_rates_from_to": "Pomi\u0119dzy {from} i {to} (i odwrotnie)",
"exchange_rates_intro_rates": "Firefly III bla bla bla exchange rates. Inverse is automatically calculated if not provided. Will go back to last found rate.", "exchange_rates_intro_rates": "Firefly III bla bla bla kurs wymiany. Odwrotno\u015b\u0107 jest obliczana automatycznie, je\u015bli nie zosta\u0142a podana. Zostanie u\u017cyty ostatni znaleziony kurs.",
"header_exchange_rates_rates": "Exchange rates", "header_exchange_rates_rates": "Kursy wymiany",
"header_exchange_rates_table": "Table with exchange rates", "header_exchange_rates_table": "Tabela z kursami wymiany walut",
"help_rate_form": "On this day, how many {to} will you get for one {from}?", "help_rate_form": "W tym dniu, ile {to} otrzymasz za jeden {from}?",
"add_new_rate": "Add a new exchange rate", "add_new_rate": "Dodaj nowy kurs wymiany",
"save_new_rate": "Save new rate" "save_new_rate": "Zapisz nowy kurs"
}, },
"form": { "form": {
"url": "URL", "url": "URL",
@@ -158,7 +158,7 @@
"webhook_delivery": "Dor\u0119czenie", "webhook_delivery": "Dor\u0119czenie",
"from_currency_to_currency": "{from} &rarr; {to}", "from_currency_to_currency": "{from} &rarr; {to}",
"to_currency_from_currency": "{to} &rarr; {from}", "to_currency_from_currency": "{to} &rarr; {from}",
"rate": "Rate" "rate": "Kurs"
}, },
"list": { "list": {
"active": "Jest aktywny?", "active": "Jest aktywny?",

View File

@@ -1320,9 +1320,9 @@ return [
'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?', 'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?',
'pref_locale_help' => 'Firefly III allows you to set other local settings, like how currencies, numbers and dates are formatted. Entries in this list may not be supported by your system. Firefly III doesn\'t have the correct date settings for every locale; contact me for improvements.', 'pref_locale_help' => 'Firefly III allows you to set other local settings, like how currencies, numbers and dates are formatted. Entries in this list may not be supported by your system. Firefly III doesn\'t have the correct date settings for every locale; contact me for improvements.',
'pref_locale_no_demo' => 'This feature won\'t work for the demo user.', 'pref_locale_no_demo' => 'This feature won\'t work for the demo user.',
'pref_convert_to_native' => 'Display amounts in your native currency', 'pref_convert_to_native' => 'Display amounts in your native currency',
'pref_convert_to_native_help' => 'This option will make Firefly III try to display and show your native currency in as many places as possible, converting amounts where necessary. This sacrifices accuracy for ease of use, because conversion is not always exact. Please verify that Firefly III has the necessary conversion rates on the "exchange rates"-page.', 'pref_convert_to_native_help' => 'This option will make Firefly III try to display and show your native currency in as many places as possible, converting amounts where necessary. This sacrifices accuracy for ease of use, because conversion is not always exact. Please verify that Firefly III has the necessary conversion rates on the "exchange rates"-page.',
'pref_convert_native_help' => 'Display native amounts', 'pref_convert_native_help' => 'Display native amounts',
'pref_custom_fiscal_year' => 'Fiscal year settings', 'pref_custom_fiscal_year' => 'Fiscal year settings',
'pref_custom_fiscal_year_label' => 'Enabled', 'pref_custom_fiscal_year_label' => 'Enabled',
'pref_custom_fiscal_year_help' => 'In countries that use a financial year other than January 1 to December 31, you can switch this on and specify start / end days of the fiscal year', 'pref_custom_fiscal_year_help' => 'In countries that use a financial year other than January 1 to December 31, you can switch this on and specify start / end days of the fiscal year',