Various code cleanup and sorting.

This commit is contained in:
James Cole
2025-03-08 19:55:21 +01:00
parent 2d3d3bc0a4
commit 30b7e17b6f
60 changed files with 1402 additions and 1475 deletions

View File

@@ -97,7 +97,6 @@ class ShowController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts); $accounts = $enrichment->enrich($accounts);
@@ -133,7 +132,6 @@ class ShowController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$account = $enrichment->enrichSingle($account); $account = $enrichment->enrichSingle($account);

View File

@@ -76,7 +76,6 @@ class StoreController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$account = $enrichment->enrichSingle($account); $account = $enrichment->enrichSingle($account);

View File

@@ -80,7 +80,6 @@ class UpdateController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$account = $enrichment->enrichSingle($account); $account = $enrichment->enrichSingle($account);

View File

@@ -84,7 +84,6 @@ class ListController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts); $accounts = $enrichment->enrich($accounts);

View File

@@ -107,7 +107,6 @@ class ListController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts); $accounts = $enrichment->enrich($accounts);

View File

@@ -88,7 +88,6 @@ class AccountController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->nativeCurrency); $enrichment->setNative($this->nativeCurrency);
$accounts = $enrichment->enrich($accounts); $accounts = $enrichment->enrich($accounts);

View File

@@ -76,7 +76,7 @@ class ValidatesEnvironmentVariables extends Command
private function validateGuard(): void private function validateGuard(): void
{ {
$guard = env('AUTHENTICATION_GUARD', 'web'); $guard = config('auth.defaults.guard');
if ('web' !== $guard && 'remote_user_guard' !== $guard) { if ('web' !== $guard && 'remote_user_guard' !== $guard) {
$this->friendlyError(sprintf('AUTHENTICATION_GUARD "%s" is not a valid guard for Firefly III.', $guard)); $this->friendlyError(sprintf('AUTHENTICATION_GUARD "%s" is not a valid guard for Firefly III.', $guard));
$this->friendlyError('Please check your .env file and make sure you use a valid setting.'); $this->friendlyError('Please check your .env file and make sure you use a valid setting.');
@@ -87,7 +87,7 @@ class ValidatesEnvironmentVariables extends Command
private function validateStaticToken(): void private function validateStaticToken(): void
{ {
$token = (string) env('STATIC_CRON_TOKEN', ''); $token = (string) config('firefly.static_cron_token');
if (0 !== strlen($token) && 32 !== strlen($token)) { if (0 !== strlen($token) && 32 !== strlen($token)) {
$this->friendlyError('STATIC_CRON_TOKEN must be empty or a 32-character string.'); $this->friendlyError('STATIC_CRON_TOKEN must be empty or a 32-character string.');
$this->friendlyError('Please check your .env file and make sure you use a valid setting.'); $this->friendlyError('Please check your .env file and make sure you use a valid setting.');

View File

@@ -88,7 +88,8 @@ class AccountObserver
} }
$journalIds = Transaction::where('account_id', $account->id)->get(['transactions.transaction_journal_id'])->pluck('transaction_journal_id')->toArray(); $journalIds = Transaction::where('account_id', $account->id)->get(['transactions.transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
$groupIds = TransactionJournal::whereIn('id', $journalIds)->get(['transaction_journals.transaction_group_id'])->pluck('transaction_group_id')->toArray(); $groupIds = TransactionJournal::whereIn('id', $journalIds)->get(['transaction_journals.transaction_group_id'])->pluck('transaction_group_id')->toArray(); // @phpstan-ignore-line
if (count($journalIds) > 0) { if (count($journalIds) > 0) {
Transaction::whereIn('transaction_journal_id', $journalIds)->delete(); Transaction::whereIn('transaction_journal_id', $journalIds)->delete();
TransactionJournal::whereIn('id', $journalIds)->delete(); TransactionJournal::whereIn('id', $journalIds)->delete();

View File

@@ -47,10 +47,10 @@ use Illuminate\Support\Facades\Log;
*/ */
class NetWorth implements NetWorthInterface class NetWorth implements NetWorthInterface
{ {
private AccountRepositoryInterface $accountRepository; private AccountRepositoryInterface $accountRepository;
private CurrencyRepositoryInterface $currencyRepos; private CurrencyRepositoryInterface $currencyRepos;
private User $user; private User $user; // @phpstan-ignore-line
private ?UserGroup $userGroup; private ?UserGroup $userGroup; // @phpstan-ignore-line
/** /**
* This method collects the user's net worth in ALL the user's currencies * This method collects the user's net worth in ALL the user's currencies
@@ -74,29 +74,29 @@ class NetWorth implements NetWorthInterface
return $cache->get(); return $cache->get();
} }
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s'))); Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
$default = Amount::getNativeCurrency(); $default = Amount::getNativeCurrency();
$netWorth = []; $netWorth = [];
Log::debug(sprintf('NetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s'))); Log::debug(sprintf('NetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
$balances = Steam::finalAccountsBalance($accounts, $date); $balances = Steam::finalAccountsBalance($accounts, $date);
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name)); Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name));
$currency = $this->accountRepository->getAccountCurrency($account) ?? $default; $currency = $this->accountRepository->getAccountCurrency($account) ?? $default;
$useNative = $convertToNative && $default->id !== $currency->id; $useNative = $convertToNative && $default->id !== $currency->id;
$currency = $useNative ? $default : $currency; $currency = $useNative ? $default : $currency;
$currencyCode = $currency->code; $currencyCode = $currency->code;
$balance = '0'; $balance = '0';
$nativeBalance = '0'; $nativeBalance = '0';
if (array_key_exists($account->id, $balances)) { if (array_key_exists($account->id, $balances)) {
$balance = $balances[$account->id]['balance'] ?? '0'; $balance = $balances[$account->id]['balance'] ?? '0';
$nativeBalance = $balances[$account->id]['native_balance'] ?? '0'; $nativeBalance = $balances[$account->id]['native_balance'] ?? '0';
} }
Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance)); Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance));
// always subtract virtual balance again. // always subtract virtual balance again.
$balance = '' !== (string) $account->virtual_balance ? bcsub($balance, $account->virtual_balance) : $balance; $balance = '' !== (string) $account->virtual_balance ? bcsub($balance, $account->virtual_balance) : $balance;
$nativeBalance = '' !== (string) $account->native_virtual_balance ? bcsub($nativeBalance, $account->native_virtual_balance) : $nativeBalance; $nativeBalance = '' !== (string) $account->native_virtual_balance ? bcsub($nativeBalance, $account->native_virtual_balance) : $nativeBalance;
$amountToUse = $useNative ? $nativeBalance : $balance; $amountToUse = $useNative ? $nativeBalance : $balance;
Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse)); Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse));
$netWorth[$currencyCode] ??= [ $netWorth[$currencyCode] ??= [
@@ -115,27 +115,23 @@ class NetWorth implements NetWorthInterface
return $netWorth; return $netWorth;
} }
public function setUser(null|Authenticatable|User $user): void public function setUser(null | Authenticatable | User $user): void
{ {
if (!$user instanceof User) { if (!$user instanceof User) {
return; return;
} }
$this->user = $user; $this->user = $user;
$this->userGroup = null; $this->setUserGroup($user->userGroup);
// make repository:
$this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUser($this->user);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->currencyRepos->setUser($this->user);
} }
public function setUserGroup(UserGroup $userGroup): void public function setUserGroup(UserGroup $userGroup): void
{ {
$this->userGroup = $userGroup; $this->userGroup = $userGroup;
$this->accountRepository = app(AccountRepositoryInterface::class); $this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUserGroup($userGroup); $this->accountRepository->setUserGroup($userGroup);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->currencyRepos->setUserGroup($this->userGroup);
} }
/** /**
@@ -151,16 +147,16 @@ class NetWorth implements NetWorthInterface
Log::debug(sprintf('SumNetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s'))); Log::debug(sprintf('SumNetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
$balances = Steam::finalAccountsBalance($accounts, $date); $balances = Steam::finalAccountsBalance($accounts, $date);
foreach ($accounts as $account) { foreach ($accounts as $account) {
$currency = $this->accountRepository->getAccountCurrency($account); $currency = $this->accountRepository->getAccountCurrency($account);
$balance = $balances[$account->id]['balance'] ?? '0'; $balance = $balances[$account->id]['balance'] ?? '0';
// always subtract virtual balance. // always subtract virtual balance.
$virtualBalance = $account->virtual_balance; $virtualBalance = $account->virtual_balance;
if ('' !== $virtualBalance) { if ('' !== $virtualBalance) {
$balance = bcsub($balance, $virtualBalance); $balance = bcsub($balance, $virtualBalance);
} }
$return[$currency->id] ??= [ $return[$currency->id] ??= [
'id' => (string) $currency->id, 'id' => (string) $currency->id,
'name' => $currency->name, 'name' => $currency->name,
'symbol' => $currency->symbol, 'symbol' => $currency->symbol,

View File

@@ -148,7 +148,6 @@ class IndexController extends Controller
// enrich each account. // enrich each account.
$enrichment = new AccountEnrichment(); $enrichment = new AccountEnrichment();
$enrichment->setUser(auth()->user()); $enrichment->setUser(auth()->user());
$enrichment->setConvertToNative($this->convertToNative);
$enrichment->setNative($this->defaultCurrency); $enrichment->setNative($this->defaultCurrency);
$return = []; $return = [];
@@ -158,6 +157,7 @@ class IndexController extends Controller
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
/** @var Account $account */
$account = $enrichment->enrichSingle($account); $account = $enrichment->enrichSingle($account);
$array = $accountTransformer->transform($account); $array = $accountTransformer->transform($account);
$accountId = (int) $array['id']; $accountId = (int) $array['id'];

View File

@@ -45,6 +45,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Override;
/** /**
* Class AccountRepository. * Class AccountRepository.
@@ -65,12 +66,6 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
return true; return true;
} }
#[\Override]
public function getAccountBalances(Account $account): Collection
{
return $account->accountBalances;
}
/** /**
* Find account with same name OR same IBAN or both, but not the same type or ID. * Find account with same name OR same IBAN or both, but not the same type or ID.
*/ */
@@ -81,8 +76,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
$byName = $this->user->accounts()->where('name', $account->name) $byName = $this->user->accounts()->where('name', $account->name)
->where('id', '!=', $account->id)->first() ->where('id', '!=', $account->id)->first();
;
if (null !== $byName) { if (null !== $byName) {
$result->push($account); $result->push($account);
$result->push($byName); $result->push($byName);
@@ -91,8 +85,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
} }
if (null !== $account->iban) { if (null !== $account->iban) {
$byIban = $this->user->accounts()->where('iban', $account->iban) $byIban = $this->user->accounts()->where('iban', $account->iban)
->where('id', '!=', $account->id)->first() ->where('id', '!=', $account->id)->first();
;
if (null !== $byIban) { if (null !== $byIban) {
$result->push($account); $result->push($account);
$result->push($byIban); $result->push($byIban);
@@ -118,8 +111,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
$q1->where('account_meta.name', '=', 'account_number'); $q1->where('account_meta.name', '=', 'account_number');
$q1->where('account_meta.data', '=', $json); $q1->where('account_meta.data', '=', $json);
} }
) );
;
if (0 !== count($types)) { if (0 !== count($types)) {
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); $dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
@@ -146,7 +138,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function findByName(string $name, array $types): ?Account public function findByName(string $name, array $types): ?Account
{ {
$query = $this->user->accounts(); $query = $this->user->accounts();
if (0 !== count($types)) { if (0 !== count($types)) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
@@ -168,6 +160,12 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
return $account; return $account;
} }
#[Override]
public function getAccountBalances(Account $account): Collection
{
return $account->accountBalances;
}
/** /**
* Return account type or null if not found. * Return account type or null if not found.
*/ */
@@ -194,10 +192,10 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
{ {
$query = $this->user->accounts()->with( $query = $this->user->accounts()->with(
[ // @phpstan-ignore-line [ // @phpstan-ignore-line
'accountmeta' => static function (HasMany $query): void { 'accountmeta' => static function (HasMany $query): void {
$query->where('name', 'account_role'); $query->where('name', 'account_role');
}, },
'attachments', 'attachments',
] ]
); );
if (0 !== count($types)) { if (0 !== count($types)) {
@@ -213,7 +211,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function getAttachments(Account $account): Collection public function getAttachments(Account $account): Collection
{ {
$set = $account->attachments()->get(); $set = $account->attachments()->get();
/** @var Storage $disk */ /** @var Storage $disk */
$disk = Storage::disk('upload'); $disk = Storage::disk('upload');
@@ -235,7 +233,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function getCashAccount(): Account public function getCashAccount(): Account
{ {
/** @var AccountType $type */ /** @var AccountType $type */
$type = AccountType::where('type', AccountTypeEnum::CASH->value)->first(); $type = AccountType::where('type', AccountTypeEnum::CASH->value)->first();
/** @var AccountFactory $factory */ /** @var AccountFactory $factory */
$factory = app(AccountFactory::class); $factory = app(AccountFactory::class);
@@ -247,10 +245,9 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function getCreditTransactionGroup(Account $account): ?TransactionGroup public function getCreditTransactionGroup(Account $account): ?TransactionGroup
{ {
$journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') $journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->transactionTypes([TransactionTypeEnum::LIABILITY_CREDIT->value]) ->transactionTypes([TransactionTypeEnum::LIABILITY_CREDIT->value])
->first(['transaction_journals.*']) ->first(['transaction_journals.*']);
;
return $journal?->transactionGroup; return $journal?->transactionGroup;
} }
@@ -259,9 +256,9 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
{ {
$query = $this->user->accounts()->with( $query = $this->user->accounts()->with(
[ // @phpstan-ignore-line [ // @phpstan-ignore-line
'accountmeta' => static function (HasMany $query): void { 'accountmeta' => static function (HasMany $query): void {
$query->where('name', 'account_role'); $query->where('name', 'account_role');
}, },
] ]
); );
if (0 !== count($types)) { if (0 !== count($types)) {
@@ -294,11 +291,10 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
*/ */
public function getOpeningBalanceAmount(Account $account, bool $convertToNative): ?string public function getOpeningBalanceAmount(Account $account, bool $convertToNative): ?string
{ {
$journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') $journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value, TransactionTypeEnum::LIABILITY_CREDIT->value]) ->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value, TransactionTypeEnum::LIABILITY_CREDIT->value])
->first(['transaction_journals.*']) ->first(['transaction_journals.*']);
;
if (null === $journal) { if (null === $journal) {
return null; return null;
} }
@@ -319,10 +315,9 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function getOpeningBalanceDate(Account $account): ?string public function getOpeningBalanceDate(Account $account): ?string
{ {
return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value, TransactionTypeEnum::LIABILITY_CREDIT->value]) ->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value, TransactionTypeEnum::LIABILITY_CREDIT->value])
->first(['transaction_journals.*'])?->date->format('Y-m-d H:i:s') ->first(['transaction_journals.*'])?->date->format('Y-m-d H:i:s');
;
} }
public function getOpeningBalanceGroup(Account $account): ?TransactionGroup public function getOpeningBalanceGroup(Account $account): ?TransactionGroup
@@ -335,10 +330,9 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function getOpeningBalance(Account $account): ?TransactionJournal public function getOpeningBalance(Account $account): ?TransactionJournal
{ {
return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value]) ->transactionTypes([TransactionTypeEnum::OPENING_BALANCE->value])
->first(['transaction_journals.*']) ->first(['transaction_journals.*']);
;
} }
public function getPiggyBanks(Account $account): Collection public function getPiggyBanks(Account $account): Collection
@@ -358,19 +352,18 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
$name = trans('firefly.reconciliation_account_name', ['name' => $account->name, 'currency' => $currency->code]); $name = trans('firefly.reconciliation_account_name', ['name' => $account->name, 'currency' => $currency->code]);
/** @var AccountType $type */ /** @var AccountType $type */
$type = AccountType::where('type', AccountTypeEnum::RECONCILIATION->value)->first(); $type = AccountType::where('type', AccountTypeEnum::RECONCILIATION->value)->first();
/** @var null|Account $current */ /** @var null|Account $current */
$current = $this->user->accounts()->where('account_type_id', $type->id) $current = $this->user->accounts()->where('account_type_id', $type->id)
->where('name', $name) ->where('name', $name)
->first() ->first();
;
if (null !== $current) { if (null !== $current) {
return $current; return $current;
} }
$data = [ $data = [
'account_type_id' => null, 'account_type_id' => null,
'account_type_name' => AccountTypeEnum::RECONCILIATION->value, 'account_type_name' => AccountTypeEnum::RECONCILIATION->value,
'active' => true, 'active' => true,
@@ -380,7 +373,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
]; ];
/** @var AccountFactory $factory */ /** @var AccountFactory $factory */
$factory = app(AccountFactory::class); $factory = app(AccountFactory::class);
$factory->setUser($account->user); $factory->setUser($account->user);
return $factory->create($data); return $factory->create($data);
@@ -388,8 +381,8 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
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)) {
@@ -453,7 +446,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function maxOrder(string $type): int public function maxOrder(string $type): int
{ {
$sets = [ $sets = [
AccountTypeEnum::ASSET->value => [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value], AccountTypeEnum::ASSET->value => [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value],
AccountTypeEnum::EXPENSE->value => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::BENEFICIARY->value], AccountTypeEnum::EXPENSE->value => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::BENEFICIARY->value],
AccountTypeEnum::REVENUE->value => [AccountTypeEnum::REVENUE->value], AccountTypeEnum::REVENUE->value => [AccountTypeEnum::REVENUE->value],
@@ -469,7 +462,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
} }
$specials = [AccountTypeEnum::CASH->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::RECONCILIATION->value]; $specials = [AccountTypeEnum::CASH->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::RECONCILIATION->value];
$order = (int) $this->getAccountsByType($specials)->max('order'); $order = (int) $this->getAccountsByType($specials)->max('order');
app('log')->debug(sprintf('Return max order of "%s" set (specials!): %d', $type, $order)); app('log')->debug(sprintf('Return max order of "%s" set (specials!): %d', $type, $order));
return $order; return $order;
@@ -520,13 +513,12 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
{ {
/** @var null|TransactionJournal $first */ /** @var null|TransactionJournal $first */
$first = $account->transactions() $first = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'ASC') ->orderBy('transaction_journals.date', 'ASC')
->orderBy('transaction_journals.order', 'DESC') ->orderBy('transaction_journals.order', 'DESC')
->where('transaction_journals.user_id', $this->user->id) ->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.id', 'ASC') ->orderBy('transaction_journals.id', 'ASC')
->first(['transaction_journals.id']) ->first(['transaction_journals.id']);
;
if (null !== $first) { if (null !== $first) {
/** @var null|TransactionJournal */ /** @var null|TransactionJournal */
return TransactionJournal::find($first->id); return TransactionJournal::find($first->id);
@@ -562,11 +554,10 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
} }
} }
// reset the rest to zero. // reset the rest to zero.
$all = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value]; $all = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value];
$this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') $this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereNotIn('account_types.type', $all) ->whereNotIn('account_types.type', $all)
->update(['order' => 0]) ->update(['order' => 0]);
;
} }
/** /**
@@ -583,12 +574,11 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function searchAccount(string $query, array $types, int $limit): Collection public function searchAccount(string $query, array $types, int $limit): Collection
{ {
$dbQuery = $this->user->accounts() $dbQuery = $this->user->accounts()
->where('active', true) ->where('active', true)
->orderBy('accounts.order', 'ASC') ->orderBy('accounts.order', 'ASC')
->orderBy('accounts.account_type_id', 'ASC') ->orderBy('accounts.account_type_id', 'ASC')
->orderBy('accounts.name', 'ASC') ->orderBy('accounts.name', 'ASC')
->with(['accountType']) ->with(['accountType']);
;
if ('' !== $query) { if ('' !== $query) {
// split query on spaces just in case: // split query on spaces just in case:
$parts = explode(' ', $query); $parts = explode(' ', $query);
@@ -608,13 +598,12 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function searchAccountNr(string $query, array $types, int $limit): Collection public function searchAccountNr(string $query, array $types, int $limit): Collection
{ {
$dbQuery = $this->user->accounts()->distinct() $dbQuery = $this->user->accounts()->distinct()
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('accounts.active', true) ->where('accounts.active', true)
->orderBy('accounts.order', 'ASC') ->orderBy('accounts.order', 'ASC')
->orderBy('accounts.account_type_id', 'ASC') ->orderBy('accounts.account_type_id', 'ASC')
->orderBy('accounts.name', 'ASC') ->orderBy('accounts.name', 'ASC')
->with(['accountType', 'accountMeta']) ->with(['accountType', 'accountMeta']);
;
if ('' !== $query) { if ('' !== $query) {
// split query on spaces just in case: // split query on spaces just in case:
$parts = explode(' ', $query); $parts = explode(' ', $query);

View File

@@ -52,7 +52,6 @@ interface AccountRepositoryInterface
* Moved here from account CRUD. * Moved here from account CRUD.
*/ */
public function count(array $types): int; public function count(array $types): int;
public function getAccountBalances(Account $account): Collection;
/** /**
* Moved here from account CRUD. * Moved here from account CRUD.
@@ -72,6 +71,8 @@ interface AccountRepositoryInterface
public function findByName(string $name, array $types): ?Account; public function findByName(string $name, array $types): ?Account;
public function getAccountBalances(Account $account): Collection;
public function getAccountCurrency(Account $account): ?TransactionCurrency; public function getAccountCurrency(Account $account): ?TransactionCurrency;
/** /**

View File

@@ -47,28 +47,28 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
*/ */
public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): array public function getAccountReport(Collection $accounts, Carbon $start, Carbon $end): array
{ {
$yesterday = clone $start; $yesterday = clone $start;
$yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including. $yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including.
$end->endOfDay(); // needs to be end of day to be correct. $end->endOfDay(); // needs to be end of day to be correct.
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $yesterday->format('Y-m-d H:i:s'))); Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $yesterday->format('Y-m-d H:i:s')));
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
$startSet = Steam::finalAccountsBalance($accounts, $yesterday); $startSet = Steam::finalAccountsBalance($accounts, $yesterday);
$endSet = Steam::finalAccountsBalance($accounts, $end); $endSet = Steam::finalAccountsBalance($accounts, $end);
Log::debug('Start of accountreport'); Log::debug('Start of accountreport');
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
$return = [ $return = [
'accounts' => [], 'accounts' => [],
'sums' => [], 'sums' => [],
]; ];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
$id = $account->id; $id = $account->id;
$currency = $repository->getAccountCurrency($account) ?? $defaultCurrency; $currency = $repository->getAccountCurrency($account) ?? $defaultCurrency;
$return['sums'][$currency->id] ??= [ $return['sums'][$currency->id] ??= [
'start' => '0', 'start' => '0',
'end' => '0', 'end' => '0',
@@ -79,7 +79,7 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
]; ];
$entry = [ $entry = [
'name' => $account->name, 'name' => $account->name,
'id' => $account->id, 'id' => $account->id,
'currency_id' => $currency->id, 'currency_id' => $currency->id,
@@ -90,9 +90,9 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
]; ];
// get first journal date: // get first journal date:
$first = $repository->oldestJournal($account); $first = $repository->oldestJournal($account);
$entry['start_balance'] = $startSet[$account->id]['balance'] ?? '0'; $entry['start_balance'] = $startSet[$account->id]['balance'] ?? '0';
$entry['end_balance'] = $endSet[$account->id]['balance'] ?? '0'; $entry['end_balance'] = $endSet[$account->id]['balance'] ?? '0';
// first journal exists, and is on start, then this is the actual opening balance: // first journal exists, and is on start, then this is the actual opening balance:
if (null !== $first && $first->date->isSameDay($yesterday) && TransactionTypeEnum::OPENING_BALANCE->value === $first->transactionType->type) { if (null !== $first && $first->date->isSameDay($yesterday) && TransactionTypeEnum::OPENING_BALANCE->value === $first->transactionType->type) {
@@ -127,13 +127,13 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$collector->setSourceAccounts($accounts)->setRange($start, $end); $collector->setSourceAccounts($accounts)->setRange($start, $end);
$collector->excludeDestinationAccounts($accounts); $collector->excludeDestinationAccounts($accounts);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::TRANSFER->value])->withAccountInformation(); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::TRANSFER->value])->withAccountInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$report = $this->groupExpenseByDestination($journals); $report = $this->groupExpenseByDestination($journals);
// sort the result // sort the result
// Obtain a list of columns // Obtain a list of columns
$sum = []; $sum = [];
foreach ($report['accounts'] as $accountId => $row) { foreach ($report['accounts'] as $accountId => $row) {
$sum[$accountId] = (float) $row['sum']; // intentional float $sum[$accountId] = (float) $row['sum']; // intentional float
} }
@@ -151,9 +151,9 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
/** @var CurrencyRepositoryInterface $currencyRepos */ /** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class); $currencyRepos = app(CurrencyRepositoryInterface::class);
$currencies = [$defaultCurrency->id => $defaultCurrency]; $currencies = [$defaultCurrency->id => $defaultCurrency];
$report = [ $report = [
'accounts' => [], 'accounts' => [],
'sums' => [], 'sums' => [],
]; ];
@@ -163,8 +163,8 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$sourceId = (int) $journal['destination_account_id']; $sourceId = (int) $journal['destination_account_id'];
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$key = sprintf('%s-%s', $sourceId, $currencyId); $key = sprintf('%s-%s', $sourceId, $currencyId);
$currencies[$currencyId] ??= $currencyRepos->find($currencyId); $currencies[$currencyId] ??= $currencyRepos->find($currencyId);
$report['accounts'][$key] ??= [ $report['accounts'][$key] ??= [
'id' => $sourceId, 'id' => $sourceId,
'name' => $journal['destination_account_name'], 'name' => $journal['destination_account_name'],
'sum' => '0', 'sum' => '0',
@@ -189,7 +189,7 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$report['accounts'][$key]['average'] = bcdiv($report['accounts'][$key]['sum'], (string) $report['accounts'][$key]['count']); $report['accounts'][$key]['average'] = bcdiv($report['accounts'][$key]['sum'], (string) $report['accounts'][$key]['count']);
} }
$currencyId = $report['accounts'][$key]['currency_id']; $currencyId = $report['accounts'][$key]['currency_id'];
$report['sums'][$currencyId] ??= [ $report['sums'][$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => $report['accounts'][$key]['currency_id'], 'currency_id' => $report['accounts'][$key]['currency_id'],
'currency_name' => $report['accounts'][$key]['currency_name'], 'currency_name' => $report['accounts'][$key]['currency_name'],
@@ -217,11 +217,11 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$collector->setDestinationAccounts($accounts)->setRange($start, $end); $collector->setDestinationAccounts($accounts)->setRange($start, $end);
$collector->excludeSourceAccounts($accounts); $collector->excludeSourceAccounts($accounts);
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value])->withAccountInformation(); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value])->withAccountInformation();
$report = $this->groupIncomeBySource($collector->getExtractedJournals()); $report = $this->groupIncomeBySource($collector->getExtractedJournals());
// sort the result // sort the result
// Obtain a list of columns // Obtain a list of columns
$sum = []; $sum = [];
foreach ($report['accounts'] as $accountId => $row) { foreach ($report['accounts'] as $accountId => $row) {
$sum[$accountId] = (float) $row['sum']; // intentional float $sum[$accountId] = (float) $row['sum']; // intentional float
} }
@@ -239,20 +239,20 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
/** @var CurrencyRepositoryInterface $currencyRepos */ /** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class); $currencyRepos = app(CurrencyRepositoryInterface::class);
$currencies = [$defaultCurrency->id => $defaultCurrency]; $currencies = [$defaultCurrency->id => $defaultCurrency];
$report = [ $report = [
'accounts' => [], 'accounts' => [],
'sums' => [], 'sums' => [],
]; ];
/** @var array $journal */ /** @var array $journal */
foreach ($array as $journal) { foreach ($array as $journal) {
$sourceId = (int) $journal['source_account_id']; $sourceId = (int) $journal['source_account_id'];
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$key = sprintf('%s-%s', $sourceId, $currencyId); $key = sprintf('%s-%s', $sourceId, $currencyId);
if (!array_key_exists($key, $report['accounts'])) { if (!array_key_exists($key, $report['accounts'])) {
$currencies[$currencyId] ??= $currencyRepos->find($currencyId); $currencies[$currencyId] ??= $currencyRepos->find($currencyId);
$report['accounts'][$key] = [ $report['accounts'][$key] = [
'id' => $sourceId, 'id' => $sourceId,
'name' => $journal['source_account_name'], 'name' => $journal['source_account_name'],
@@ -276,7 +276,7 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$report['accounts'][$key]['average'] = bcdiv($report['accounts'][$key]['sum'], (string) $report['accounts'][$key]['count']); $report['accounts'][$key]['average'] = bcdiv($report['accounts'][$key]['sum'], (string) $report['accounts'][$key]['count']);
} }
$currencyId = $report['accounts'][$key]['currency_id']; $currencyId = $report['accounts'][$key]['currency_id'];
$report['sums'][$currencyId] ??= [ $report['sums'][$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => $report['accounts'][$key]['currency_id'], 'currency_id' => $report['accounts'][$key]['currency_id'],
'currency_name' => $report['accounts'][$key]['currency_name'], 'currency_name' => $report['accounts'][$key]['currency_name'],

View File

@@ -70,8 +70,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
{ {
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'currency_id' => $journal['currency_id'], 'currency_id' => $journal['currency_id'],
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -123,7 +123,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $expense = null, ?Collection $expense = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency);
return $this->groupByCurrency($journals, 'negative'); return $this->groupByCurrency($journals, 'negative');
@@ -140,7 +141,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $opposing = null, ?Collection $opposing = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$start->startOfDay(); $start->startOfDay();
$end->endOfDay(); $end->endOfDay();
@@ -173,15 +175,14 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
if (null !== $currency) { if (null !== $currency) {
$collector->setCurrency($currency); $collector->setCurrency($currency);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
// same but for foreign currencies: // same but for foreign currencies:
if (null !== $currency) { if (null !== $currency) {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([$type])->withAccountInformation() $collector->setUser($this->user)->setRange($start, $end)->setTypes([$type])->withAccountInformation()
->setForeignCurrency($currency) ->setForeignCurrency($currency);
;
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
if (null !== $accounts) { if (null !== $accounts) {
$collector->setSourceAccounts($accounts); $collector->setSourceAccounts($accounts);
@@ -199,10 +200,10 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
} }
$result = $collector->getExtractedJournals(); $result = $collector->getExtractedJournals();
// do not use array_merge because you want keys to overwrite (otherwise you get double results): // do not use array_merge because you want keys to overwrite (otherwise you get double results):
$journals = $result + $journals; $journals = $result + $journals;
} }
return $journals; return $journals;
@@ -224,7 +225,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $expense = null, ?Collection $expense = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'destination', 'negative'); return $this->groupByDirection($journals, 'destination', 'negative');
@@ -246,7 +248,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $expense = null, ?Collection $expense = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::WITHDRAWAL->value, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'source', 'negative'); return $this->groupByDirection($journals, 'source', 'negative');
@@ -261,7 +264,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $revenue = null, ?Collection $revenue = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency);
return $this->groupByCurrency($journals, 'positive'); return $this->groupByCurrency($journals, 'positive');
@@ -276,7 +280,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $revenue = null, ?Collection $revenue = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'destination', 'positive'); return $this->groupByDirection($journals, 'destination', 'positive');
@@ -291,7 +296,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $revenue = null, ?Collection $revenue = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
$journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency); $journals = $this->getTransactionsForSum(TransactionTypeEnum::DEPOSIT->value, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'source', 'positive'); return $this->groupByDirection($journals, 'source', 'positive');
@@ -312,7 +318,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
foreach ($journals as $journal) { foreach ($journals as $journal) {
$return = $this->groupByEitherJournal($return, $journal); $return = $this->groupByEitherJournal($return, $journal);
} }
$final = []; $final = [];
foreach ($return as $array) { foreach ($return as $array) {
$array['difference_float'] = (float) $array['difference']; $array['difference_float'] = (float) $array['difference'];
$array['in_float'] = (float) $array['in']; $array['in_float'] = (float) $array['in'];
@@ -325,12 +331,12 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
private function groupByEitherJournal(array $return, array $journal): array private function groupByEitherJournal(array $return, array $journal): array
{ {
$sourceId = $journal['source_account_id']; $sourceId = $journal['source_account_id'];
$destinationId = $journal['destination_account_id']; $destinationId = $journal['destination_account_id'];
$currencyId = $journal['currency_id']; $currencyId = $journal['currency_id'];
$sourceKey = sprintf('%d-%d', $currencyId, $sourceId); $sourceKey = sprintf('%d-%d', $currencyId, $sourceId);
$destKey = sprintf('%d-%d', $currencyId, $destinationId); $destKey = sprintf('%d-%d', $currencyId, $destinationId);
$amount = app('steam')->positive($journal['amount']); $amount = app('steam')->positive($journal['amount']);
// source first // source first
$return[$sourceKey] ??= [ $return[$sourceKey] ??= [
@@ -347,7 +353,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
]; ];
// dest next: // dest next:
$return[$destKey] ??= [ $return[$destKey] ??= [
'id' => (string) $destinationId, 'id' => (string) $destinationId,
'name' => $journal['destination_account_name'], 'name' => $journal['destination_account_name'],
'difference' => '0', 'difference' => '0',
@@ -365,15 +371,15 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']); $return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']);
// destination account? money comes in: // destination account? money comes in:
$return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount); $return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount);
$return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']); $return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']);
// foreign currency // foreign currency
if (null !== $journal['foreign_currency_id'] && null !== $journal['foreign_amount']) { if (null !== $journal['foreign_currency_id'] && null !== $journal['foreign_amount']) {
$currencyId = $journal['foreign_currency_id']; $currencyId = $journal['foreign_currency_id'];
$sourceKey = sprintf('%d-%d', $currencyId, $sourceId); $sourceKey = sprintf('%d-%d', $currencyId, $sourceId);
$destKey = sprintf('%d-%d', $currencyId, $destinationId); $destKey = sprintf('%d-%d', $currencyId, $destinationId);
$amount = app('steam')->positive($journal['foreign_amount']); $amount = app('steam')->positive($journal['foreign_amount']);
// same as above: // same as above:
// source first // source first
@@ -391,7 +397,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
]; ];
// dest next: // dest next:
$return[$destKey] ??= [ $return[$destKey] ??= [
'id' => (string) $destinationId, 'id' => (string) $destinationId,
'name' => $journal['destination_account_name'], 'name' => $journal['destination_account_name'],
'difference' => '0', 'difference' => '0',
@@ -408,8 +414,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']); $return[$sourceKey]['difference'] = bcadd($return[$sourceKey]['out'], $return[$sourceKey]['in']);
// destination account? money comes in: // destination account? money comes in:
$return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount); $return[$destKey]['in'] = bcadd($return[$destKey]['in'], $amount);
$return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']); $return[$destKey]['difference'] = bcadd($return[$destKey]['out'], $return[$destKey]['in']);
} }
return $return; return $return;

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Attachment; namespace FireflyIII\Repositories\Attachment;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AttachmentFactory; use FireflyIII\Factory\AttachmentFactory;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
@@ -35,6 +36,7 @@ use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use League\Flysystem\UnableToDeleteFile; use League\Flysystem\UnableToDeleteFile;
use LogicException;
/** /**
* Class AttachmentRepository. * Class AttachmentRepository.
@@ -44,14 +46,14 @@ class AttachmentRepository implements AttachmentRepositoryInterface, UserGroupIn
use UserGroupTrait; use UserGroupTrait;
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroy(Attachment $attachment): bool public function destroy(Attachment $attachment): bool
{ {
/** @var AttachmentHelperInterface $helper */ /** @var AttachmentHelperInterface $helper */
$helper = app(AttachmentHelperInterface::class); $helper = app(AttachmentHelperInterface::class);
$path = $helper->getAttachmentLocation($attachment); $path = $helper->getAttachmentLocation($attachment);
try { try {
Storage::disk('upload')->delete($path); Storage::disk('upload')->delete($path);
@@ -118,7 +120,7 @@ class AttachmentRepository implements AttachmentRepositoryInterface, UserGroupIn
/** @var AttachmentFactory $factory */ /** @var AttachmentFactory $factory */
$factory = app(AttachmentFactory::class); $factory = app(AttachmentFactory::class);
$factory->setUser($this->user); $factory->setUser($this->user);
$result = $factory->create($data); $result = $factory->create($data);
if (null === $result) { if (null === $result) {
throw new FireflyException('Could not store attachment.'); throw new FireflyException('Could not store attachment.');
} }
@@ -158,14 +160,14 @@ class AttachmentRepository implements AttachmentRepositoryInterface, UserGroupIn
if (null !== $dbNote) { if (null !== $dbNote) {
try { try {
$dbNote->delete(); $dbNote->delete();
} catch (\LogicException $e) { } catch (LogicException $e) {
app('log')->error($e->getMessage()); app('log')->error($e->getMessage());
} }
} }
return true; return true;
} }
$dbNote = $attachment->notes()->first(); $dbNote = $attachment->notes()->first();
if (null === $dbNote) { if (null === $dbNote) {
$dbNote = new Note(); $dbNote = new Note();
$dbNote->noteable()->associate($attachment); $dbNote->noteable()->associate($attachment);

View File

@@ -41,7 +41,7 @@ class ALERepository implements ALERepositoryInterface
public function store(array $data): AuditLogEntry public function store(array $data): AuditLogEntry
{ {
$auditLogEntry = new AuditLogEntry(); $auditLogEntry = new AuditLogEntry();
$auditLogEntry->auditable()->associate($data['auditable']); $auditLogEntry->auditable()->associate($data['auditable']);
$auditLogEntry->changer()->associate($data['changer']); $auditLogEntry->changer()->associate($data['changer']);

View File

@@ -62,8 +62,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
$search->whereLike('name', sprintf('%%%s', $query)); $search->whereLike('name', sprintf('%%%s', $query));
} }
$search->orderBy('name', 'ASC') $search->orderBy('name', 'ASC')
->where('active', true) ->where('active', true);
;
return $search->take($limit)->get(); return $search->take($limit)->get();
} }
@@ -75,8 +74,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
$search->whereLike('name', sprintf('%s%%', $query)); $search->whereLike('name', sprintf('%s%%', $query));
} }
$search->orderBy('name', 'ASC') $search->orderBy('name', 'ASC')
->where('active', true) ->where('active', true);
;
return $search->take($limit)->get(); return $search->take($limit)->get();
} }
@@ -178,10 +176,9 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function getBills(): Collection public function getBills(): Collection
{ {
return $this->user->bills() return $this->user->bills()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('name', 'ASC')->get() ->orderBy('name', 'ASC')->get();
;
} }
public function getBillsForAccounts(Collection $accounts): Collection public function getBillsForAccounts(Collection $accounts): Collection
@@ -205,25 +202,24 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
return $this->user->bills() return $this->user->bills()
->leftJoin( ->leftJoin(
'transaction_journals', 'transaction_journals',
static function (JoinClause $join): void { static function (JoinClause $join): void {
$join->on('transaction_journals.bill_id', '=', 'bills.id')->whereNull('transaction_journals.deleted_at'); $join->on('transaction_journals.bill_id', '=', 'bills.id')->whereNull('transaction_journals.deleted_at');
} }
) )
->leftJoin( ->leftJoin(
'transactions', 'transactions',
static function (JoinClause $join): void { static function (JoinClause $join): void {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
} }
) )
->whereIn('transactions.account_id', $ids) ->whereIn('transactions.account_id', $ids)
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->orderBy('bills.active', 'DESC') ->orderBy('bills.active', 'DESC')
->orderBy('bills.name', 'ASC') ->orderBy('bills.name', 'ASC')
->groupBy($fields) ->groupBy($fields)
->get($fields) ->get($fields);
;
} }
/** /**
@@ -248,7 +244,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function getOverallAverage(Bill $bill): array public function getOverallAverage(Bill $bill): array
{ {
/** @var JournalRepositoryInterface $repos */ /** @var JournalRepositoryInterface $repos */
$repos = app(JournalRepositoryInterface::class); $repos = app(JournalRepositoryInterface::class);
$repos->setUser($this->user); $repos->setUser($this->user);
// get and sort on currency // get and sort on currency
@@ -261,7 +257,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
$transaction = $journal->transactions()->where('amount', '<', 0)->first(); $transaction = $journal->transactions()->where('amount', '<', 0)->first();
$currencyId = (int) $journal->transaction_currency_id; $currencyId = (int) $journal->transaction_currency_id;
$currency = $journal->transactionCurrency; $currency = $journal->transactionCurrency;
$result[$currencyId] ??= [ $result[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'native_sum' => '0', 'native_sum' => '0',
'count' => 0, 'count' => 0,
@@ -296,9 +292,8 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function getPaginator(int $size): LengthAwarePaginator public function getPaginator(int $size): LengthAwarePaginator
{ {
return $this->user->bills() return $this->user->bills()
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('name', 'ASC')->paginate($size) ->orderBy('name', 'ASC')->paginate($size);
;
} }
/** /**
@@ -311,14 +306,13 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
Log::debug(sprintf('Search for linked journals between %s and %s', $start->toW3cString(), $end->toW3cString())); Log::debug(sprintf('Search for linked journals between %s and %s', $start->toW3cString(), $end->toW3cString()));
return $bill->transactionJournals() return $bill->transactionJournals()
->before($end)->after($start)->get( ->before($end)->after($start)->get(
[ [
'transaction_journals.id', 'transaction_journals.id',
'transaction_journals.date', 'transaction_journals.date',
'transaction_journals.transaction_group_id', 'transaction_journals.transaction_group_id',
] ]
) );
;
} }
/** /**
@@ -327,11 +321,10 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function getRulesForBill(Bill $bill): Collection public function getRulesForBill(Bill $bill): Collection
{ {
return $this->user->rules() return $this->user->rules()
->leftJoin('rule_actions', 'rule_actions.rule_id', '=', 'rules.id') ->leftJoin('rule_actions', 'rule_actions.rule_id', '=', 'rules.id')
->where('rule_actions.action_type', 'link_to_bill') ->where('rule_actions.action_type', 'link_to_bill')
->where('rule_actions.action_value', $bill->name) ->where('rule_actions.action_value', $bill->name)
->get(['rules.*']) ->get(['rules.*']);
;
} }
/** /**
@@ -342,16 +335,15 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
*/ */
public function getRulesForBills(Collection $collection): array public function getRulesForBills(Collection $collection): array
{ {
$rules = $this->user->rules() $rules = $this->user->rules()
->leftJoin('rule_actions', 'rule_actions.rule_id', '=', 'rules.id') ->leftJoin('rule_actions', 'rule_actions.rule_id', '=', 'rules.id')
->where('rule_actions.action_type', 'link_to_bill') ->where('rule_actions.action_type', 'link_to_bill')
->get(['rules.id', 'rules.title', 'rule_actions.action_value', 'rules.active']) ->get(['rules.id', 'rules.title', 'rule_actions.action_value', 'rules.active']);
; $array = [];
$array = [];
/** @var Rule $rule */ /** @var Rule $rule */
foreach ($rules as $rule) { foreach ($rules as $rule) {
$array[$rule->action_value] ??= []; $array[$rule->action_value] ??= [];
$array[$rule->action_value][] = ['id' => $rule->id, 'title' => $rule->title, 'active' => $rule->active]; $array[$rule->action_value][] = ['id' => $rule->id, 'title' => $rule->title, 'active' => $rule->active];
} }
$return = []; $return = [];
@@ -365,28 +357,27 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function getYearAverage(Bill $bill, Carbon $date): array public function getYearAverage(Bill $bill, Carbon $date): array
{ {
/** @var JournalRepositoryInterface $repos */ /** @var JournalRepositoryInterface $repos */
$repos = app(JournalRepositoryInterface::class); $repos = app(JournalRepositoryInterface::class);
$repos->setUser($this->user); $repos->setUser($this->user);
// get and sort on currency // get and sort on currency
$result = []; $result = [];
$journals = $bill->transactionJournals() $journals = $bill->transactionJournals()
->where('date', '>=', $date->year.'-01-01 00:00:00') ->where('date', '>=', $date->year . '-01-01 00:00:00')
->where('date', '<=', $date->year.'-12-31 23:59:59') ->where('date', '<=', $date->year . '-12-31 23:59:59')
->get() ->get();
;
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
/** @var null|Transaction $transaction */ /** @var null|Transaction $transaction */
$transaction = $journal->transactions()->where('amount', '<', 0)->first(); $transaction = $journal->transactions()->where('amount', '<', 0)->first();
if (null === $transaction) { if (null === $transaction) {
continue; continue;
} }
$currencyId = (int) $journal->transaction_currency_id; $currencyId = (int) $journal->transaction_currency_id;
$currency = $journal->transactionCurrency; $currency = $journal->transactionCurrency;
$result[$currencyId] ??= [ $result[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'native_sum' => '0', 'native_sum' => '0',
'count' => 0, 'count' => 0,
@@ -436,7 +427,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
*/ */
public function nextExpectedMatch(Bill $bill, Carbon $date): Carbon public function nextExpectedMatch(Bill $bill, Carbon $date): Carbon
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($bill->id); $cache->addProperty($bill->id);
$cache->addProperty('nextExpectedMatch'); $cache->addProperty('nextExpectedMatch');
$cache->addProperty($date); $cache->addProperty($date);
@@ -444,17 +435,17 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
return $cache->get(); return $cache->get();
} }
// find the most recent date for this bill NOT in the future. Cache this date: // find the most recent date for this bill NOT in the future. Cache this date:
$start = clone $bill->date; $start = clone $bill->date;
$start->startOfDay(); $start->startOfDay();
app('log')->debug('nextExpectedMatch: Start is '.$start->format('Y-m-d')); app('log')->debug('nextExpectedMatch: Start is ' . $start->format('Y-m-d'));
while ($start < $date) { while ($start < $date) {
app('log')->debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d H:i:s'), $date->format('Y-m-d H:i:s'))); app('log')->debug(sprintf('$start (%s) < $date (%s)', $start->format('Y-m-d H:i:s'), $date->format('Y-m-d H:i:s')));
$start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
app('log')->debug('Start is now '.$start->format('Y-m-d H:i:s')); app('log')->debug('Start is now ' . $start->format('Y-m-d H:i:s'));
} }
$end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
$end->endOfDay(); $end->endOfDay();
// see if the bill was paid in this period. // see if the bill was paid in this period.
@@ -466,8 +457,8 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
$start = clone $end; $start = clone $end;
$end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); $end = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
} }
app('log')->debug('nextExpectedMatch: Final start is '.$start->format('Y-m-d')); app('log')->debug('nextExpectedMatch: Final start is ' . $start->format('Y-m-d'));
app('log')->debug('nextExpectedMatch: Matching end is '.$end->format('Y-m-d')); app('log')->debug('nextExpectedMatch: Matching end is ' . $end->format('Y-m-d'));
$cache->store($start); $cache->store($start);
@@ -528,8 +519,8 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
foreach ($bills as $bill) { foreach ($bills as $bill) {
/** @var Collection $set */ /** @var Collection $set */
$set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']); $set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
$currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency; $currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;
$return[(int) $currency->id] ??= [ $return[(int) $currency->id] ??= [
'id' => (string) $currency->id, 'id' => (string) $currency->id,
'name' => $currency->name, 'name' => $currency->name,
@@ -538,7 +529,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
'decimal_places' => $currency->decimal_places, 'decimal_places' => $currency->decimal_places,
'sum' => '0', 'sum' => '0',
]; ];
$setAmount = '0'; $setAmount = '0';
/** @var TransactionJournal $transactionJournal */ /** @var TransactionJournal $transactionJournal */
foreach ($set as $transactionJournal) { foreach ($set as $transactionJournal) {
@@ -555,10 +546,10 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function getActiveBills(): Collection public function getActiveBills(): Collection
{ {
return $this->user->bills() return $this->user->bills()
->where('active', true) ->where('active', true)
->orderBy('bills.name', 'ASC') ->orderBy('bills.name', 'ASC')
->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount')]) // @phpstan-ignore-line ->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount')]) // @phpstan-ignore-line
; ;
} }
public function sumUnpaidInRange(Carbon $start, Carbon $end): array public function sumUnpaidInRange(Carbon $start, Carbon $end): array
@@ -572,9 +563,9 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
/** @var Bill $bill */ /** @var Bill $bill */
foreach ($bills as $bill) { foreach ($bills as $bill) {
// app('log')->debug(sprintf('Processing bill #%d ("%s")', $bill->id, $bill->name)); // app('log')->debug(sprintf('Processing bill #%d ("%s")', $bill->id, $bill->name));
$dates = $this->getPayDatesInRange($bill, $start, $end); $dates = $this->getPayDatesInRange($bill, $start, $end);
$count = $bill->transactionJournals()->after($start)->before($end)->count(); $count = $bill->transactionJournals()->after($start)->before($end)->count();
$total = $dates->count() - $count; $total = $dates->count() - $count;
// app('log')->debug(sprintf('Pay dates: %d, count: %d, left: %d', $dates->count(), $count, $total)); // app('log')->debug(sprintf('Pay dates: %d, count: %d, left: %d', $dates->count(), $count, $total));
// app('log')->debug('dates', $dates->toArray()); // app('log')->debug('dates', $dates->toArray());
@@ -583,10 +574,10 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
// Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField)); // Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField));
if ($total > 0) { if ($total > 0) {
$currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency; $currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;
$average = bcdiv(bcadd($bill->{$maxField} ?? '0', $bill->{$minField} ?? '0'), '2'); $average = bcdiv(bcadd($bill->{$maxField} ?? '0', $bill->{$minField} ?? '0'), '2');
Log::debug(sprintf('Amount to pay is %s %s (%d times)', $currency->code, $average, $total)); Log::debug(sprintf('Amount to pay is %s %s (%d times)', $currency->code, $average, $total));
$return[$currency->id] ??= [ $return[$currency->id] ??= [
'id' => (string) $currency->id, 'id' => (string) $currency->id,
'name' => $currency->name, 'name' => $currency->name,
'symbol' => $currency->symbol, 'symbol' => $currency->symbol,
@@ -624,7 +615,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
// app('log')->debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d'))); // app('log')->debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
$currentStart = clone $nextExpectedMatch; $currentStart = clone $nextExpectedMatch;
} }
return $set; return $set;

View File

@@ -48,9 +48,9 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
/** @var AvailableBudget $availableBudget */ /** @var AvailableBudget $availableBudget */
foreach ($availableBudgets as $availableBudget) { foreach ($availableBudgets as $availableBudget) {
$start = $availableBudget->start_date->format('Y-m-d'); $start = $availableBudget->start_date->format('Y-m-d');
$end = $availableBudget->end_date->format('Y-m-d'); $end = $availableBudget->end_date->format('Y-m-d');
$key = sprintf('%s-%s-%s', $availableBudget->transaction_currency_id, $start, $end); $key = sprintf('%s-%s-%s', $availableBudget->transaction_currency_id, $start, $end);
if (array_key_exists($key, $exists)) { if (array_key_exists($key, $exists)) {
app('log')->debug(sprintf('Found duplicate AB: %s %s, %s-%s. Has been deleted', $availableBudget->transaction_currency_id, $availableBudget->amount, $start, $end)); app('log')->debug(sprintf('Found duplicate AB: %s %s, %s-%s. Has been deleted', $availableBudget->transaction_currency_id, $availableBudget->amount, $start, $end));
$availableBudget->delete(); $availableBudget->delete();
@@ -64,7 +64,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
*/ */
public function get(?Carbon $start = null, ?Carbon $end = null): Collection public function get(?Carbon $start = null, ?Carbon $end = null): Collection
{ {
$query = $this->user->availableBudgets()->with(['transactionCurrency']); $query = $this->user->availableBudgets()->with(['transactionCurrency']);
if (null !== $start && null !== $end) { if (null !== $start && null !== $end) {
$query->where( $query->where(
static function (Builder $q1) use ($start, $end): void { static function (Builder $q1) use ($start, $end): void {
@@ -105,23 +105,21 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
{ {
/** @var null|AvailableBudget */ /** @var null|AvailableBudget */
return $this->user->availableBudgets() return $this->user->availableBudgets()
->where('transaction_currency_id', $currency->id) ->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d')) ->where('end_date', $end->format('Y-m-d'))
->first() ->first();
;
} }
public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string
{ {
$amount = '0'; $amount = '0';
/** @var null|AvailableBudget $availableBudget */ /** @var null|AvailableBudget $availableBudget */
$availableBudget = $this->user->availableBudgets() $availableBudget = $this->user->availableBudgets()
->where('transaction_currency_id', $currency->id) ->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->first() ->where('end_date', $end->format('Y-m-d'))->first();
;
if (null !== $availableBudget) { if (null !== $availableBudget) {
$amount = $availableBudget->amount; $amount = $availableBudget->amount;
} }
@@ -134,15 +132,14 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
Log::debug(sprintf('Now in %s(%s, %s)', __METHOD__, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('Now in %s(%s, %s)', __METHOD__, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$return = []; $return = [];
$availableBudgets = $this->user->availableBudgets() $availableBudgets = $this->user->availableBudgets()
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->get() ->where('end_date', $end->format('Y-m-d'))->get();
;
Log::debug(sprintf('Found %d available budgets', $availableBudgets->count())); Log::debug(sprintf('Found %d available budgets', $availableBudgets->count()));
// use native amount if necessary? // use native amount if necessary?
$convertToNative = Amount::convertToNative($this->user); $convertToNative = Amount::convertToNative($this->user);
$default = Amount::getNativeCurrency(); $default = Amount::getNativeCurrency();
/** @var AvailableBudget $availableBudget */ /** @var AvailableBudget $availableBudget */
foreach ($availableBudgets as $availableBudget) { foreach ($availableBudgets as $availableBudget) {
@@ -187,10 +184,9 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
public function getAvailableBudgetsByExactDate(Carbon $start, Carbon $end): Collection public function getAvailableBudgetsByExactDate(Carbon $start, Carbon $end): Collection
{ {
return $this->user->availableBudgets() return $this->user->availableBudgets()
->where('start_date', '=', $start->format('Y-m-d')) ->where('start_date', '=', $start->format('Y-m-d'))
->where('end_date', '=', $end->format('Y-m-d')) ->where('end_date', '=', $end->format('Y-m-d'))
->get() ->get();
;
} }
public function getByCurrencyDate(Carbon $start, Carbon $end, TransactionCurrency $currency): ?AvailableBudget public function getByCurrencyDate(Carbon $start, Carbon $end, TransactionCurrency $currency): ?AvailableBudget
@@ -200,8 +196,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
->availableBudgets() ->availableBudgets()
->where('transaction_currency_id', $currency->id) ->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->first() ->where('end_date', $end->format('Y-m-d'))->first();
;
} }
/** /**
@@ -210,13 +205,12 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget
{ {
/** @var null|AvailableBudget */ /** @var null|AvailableBudget */
$availableBudget = $this->user->availableBudgets() $availableBudget = $this->user->availableBudgets()
->where('transaction_currency_id', $currency->id) ->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->first() ->where('end_date', $end->format('Y-m-d'))->first();
;
if (null === $availableBudget) { if (null === $availableBudget) {
$availableBudget = new AvailableBudget(); $availableBudget = new AvailableBudget();
$availableBudget->user()->associate($this->user); $availableBudget->user()->associate($this->user);
$availableBudget->transactionCurrency()->associate($currency); $availableBudget->transactionCurrency()->associate($currency);
$availableBudget->start_date = $start->startOfDay(); $availableBudget->start_date = $start->startOfDay();
@@ -236,7 +230,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
if ($start instanceof Carbon) { if ($start instanceof Carbon) {
$start = $data['start']->startOfDay(); $start = $data['start']->startOfDay();
} }
$end = $data['end']; $end = $data['end'];
if ($end instanceof Carbon) { if ($end instanceof Carbon) {
$end = $data['end']->endOfDay(); $end = $data['end']->endOfDay();
} }

View File

@@ -33,10 +33,10 @@ use FireflyIII\Models\Note;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface; use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Override;
/** /**
* Class BudgetLimitRepository * Class BudgetLimitRepository
@@ -51,10 +51,10 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
*/ */
public function budgeted(Carbon $start, Carbon $end, TransactionCurrency $currency, ?Collection $budgets = null): string public function budgeted(Carbon $start, Carbon $end, TransactionCurrency $currency, ?Collection $budgets = null): string
{ {
$query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
// same complex where query as below. // same complex where query as below.
->where( ->where(
static function (Builder $q5) use ($start, $end): void { static function (Builder $q5) use ($start, $end): void {
$q5->where( $q5->where(
static function (Builder $q1) use ($start, $end): void { static function (Builder $q1) use ($start, $end): void {
@@ -64,30 +64,27 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
$q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d')); $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d'));
} }
) )
->orWhere( ->orWhere(
static function (Builder $q3) use ($start, $end): void { static function (Builder $q3) use ($start, $end): void {
$q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d')); $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d'));
$q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d')); $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d'));
} }
) );
;
} }
) )
->orWhere( ->orWhere(
static function (Builder $q4) use ($start, $end): void { static function (Builder $q4) use ($start, $end): void {
// or start is before start AND end is after end. // or start is before start AND end is after end.
$q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d')); $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d'));
$q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d'));
} }
) );
;
} }
) )
->where('budget_limits.transaction_currency_id', $currency->id) ->where('budget_limits.transaction_currency_id', $currency->id)
->whereNull('budgets.deleted_at') ->whereNull('budgets.deleted_at')
->where('budgets.active', true) ->where('budgets.active', true)
->where('budgets.user_id', $this->user->id) ->where('budgets.user_id', $this->user->id);
;
if (null !== $budgets && $budgets->count() > 0) { if (null !== $budgets && $budgets->count() > 0) {
$query->whereIn('budget_limits.budget_id', $budgets->pluck('id')->toArray()); $query->whereIn('budget_limits.budget_id', $budgets->pluck('id')->toArray());
} }
@@ -139,19 +136,17 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
// both are NULL: // both are NULL:
if (null === $start && null === $end) { if (null === $start && null === $end) {
return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->with(['budget']) ->with(['budget'])
->where('budgets.user_id', $this->user->id) ->where('budgets.user_id', $this->user->id)
->whereNull('budgets.deleted_at') ->whereNull('budgets.deleted_at')
->get(['budget_limits.*']) ->get(['budget_limits.*']);
;
} }
// one of the two is NULL. // one of the two is NULL.
if (null === $start xor null === $end) { if (null === $start xor null === $end) {
$query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->with(['budget']) ->with(['budget'])
->whereNull('budgets.deleted_at') ->whereNull('budgets.deleted_at')
->where('budgets.user_id', $this->user->id) ->where('budgets.user_id', $this->user->id);
;
if (null !== $end) { if (null !== $end) {
// end date must be before $end. // end date must be before $end.
$query->where('end_date', '<=', $end->format('Y-m-d 00:00:00')); $query->where('end_date', '<=', $end->format('Y-m-d 00:00:00'));
@@ -166,39 +161,36 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
// neither are NULL: // neither are NULL:
return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->with(['budget']) ->with(['budget'])
->where('budgets.user_id', $this->user->id) ->where('budgets.user_id', $this->user->id)
->whereNull('budgets.deleted_at') ->whereNull('budgets.deleted_at')
->where( ->where(
static function (Builder $q5) use ($start, $end): void { static function (Builder $q5) use ($start, $end): void {
$q5->where( $q5->where(
static function (Builder $q1) use ($start, $end): void { static function (Builder $q1) use ($start, $end): void {
$q1->where( $q1->where(
static function (Builder $q2) use ($start, $end): void { static function (Builder $q2) use ($start, $end): void {
$q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d'));
$q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d')); $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d'));
} }
) )
->orWhere( ->orWhere(
static function (Builder $q3) use ($start, $end): void { static function (Builder $q3) use ($start, $end): void {
$q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d')); $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d'));
$q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d')); $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d'));
} }
) );
; }
} )
) ->orWhere(
->orWhere( static function (Builder $q4) use ($start, $end): void {
static function (Builder $q4) use ($start, $end): void { // or start is before start AND end is after end.
// or start is before start AND end is after end. $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d'));
$q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d')); $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d'));
$q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); }
} );
) }
; )->get(['budget_limits.*']);
}
)->get(['budget_limits.*'])
;
} }
public function getBudgetLimits(Budget $budget, ?Carbon $start = null, ?Carbon $end = null): Collection public function getBudgetLimits(Budget $budget, ?Carbon $start = null, ?Carbon $end = null): Collection
@@ -223,41 +215,38 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
// when both dates are set: // when both dates are set:
return $budget->budgetlimits() return $budget->budgetlimits()
->where( ->where(
static function (Builder $q5) use ($start, $end): void { static function (Builder $q5) use ($start, $end): void {
$q5->where( $q5->where(
static function (Builder $q1) use ($start, $end): void { static function (Builder $q1) use ($start, $end): void {
// budget limit ends within period // budget limit ends within period
$q1->where( $q1->where(
static function (Builder $q2) use ($start, $end): void { static function (Builder $q2) use ($start, $end): void {
$q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d 00:00:00')); $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d 00:00:00'));
$q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d 23:59:59')); $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d 23:59:59'));
} }
) )
// budget limit start within period // budget limit start within period
->orWhere( ->orWhere(
static function (Builder $q3) use ($start, $end): void { static function (Builder $q3) use ($start, $end): void {
$q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d 00:00:00')); $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d 00:00:00'));
$q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d 23:59:59')); $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d 23:59:59'));
} }
) );
; }
} )
) ->orWhere(
->orWhere( static function (Builder $q4) use ($start, $end): void {
static function (Builder $q4) use ($start, $end): void { // or start is before start AND end is after end.
// or start is before start AND end is after end. $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 23:59:59'));
$q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 23:59:59')); $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d 00:00:00'));
$q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d 00:00:00')); }
} );
) }
; )->orderBy('budget_limits.start_date', 'DESC')->get(['budget_limits.*']);
}
)->orderBy('budget_limits.start_date', 'DESC')->get(['budget_limits.*'])
;
} }
#[\Override] #[Override]
public function getNoteText(BudgetLimit $budgetLimit): string public function getNoteText(BudgetLimit $budgetLimit): string
{ {
return (string) $budgetLimit->notes()->first()?->text; return (string) $budgetLimit->notes()->first()?->text;
@@ -270,35 +259,34 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
{ {
// if no currency has been provided, use the user's default currency: // if no currency has been provided, use the user's default currency:
/** @var TransactionCurrencyFactory $factory */ /** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class); $factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null); $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
if (null === $currency) { if (null === $currency) {
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
} }
$currency->enabled = true; $currency->enabled = true;
$currency->save(); $currency->save();
// find the budget: // find the budget:
/** @var null|Budget $budget */ /** @var null|Budget $budget */
$budget = $this->user->budgets()->find((int) $data['budget_id']); $budget = $this->user->budgets()->find((int) $data['budget_id']);
if (null === $budget) { if (null === $budget) {
throw new FireflyException('200004: Budget does not exist.'); throw new FireflyException('200004: Budget does not exist.');
} }
// find limit with same date range and currency. // find limit with same date range and currency.
$limit = $budget->budgetlimits() $limit = $budget->budgetlimits()
->where('budget_limits.start_date', $data['start_date']->format('Y-m-d')) ->where('budget_limits.start_date', $data['start_date']->format('Y-m-d'))
->where('budget_limits.end_date', $data['end_date']->format('Y-m-d')) ->where('budget_limits.end_date', $data['end_date']->format('Y-m-d'))
->where('budget_limits.transaction_currency_id', $currency->id) ->where('budget_limits.transaction_currency_id', $currency->id)
->first(['budget_limits.*']) ->first(['budget_limits.*']);
;
if (null !== $limit) { if (null !== $limit) {
throw new FireflyException('200027: Budget limit already exists.'); throw new FireflyException('200027: Budget limit already exists.');
} }
app('log')->debug('No existing budget limit, create a new one'); app('log')->debug('No existing budget limit, create a new one');
// or create one and return it. // or create one and return it.
$limit = new BudgetLimit(); $limit = new BudgetLimit();
$limit->budget()->associate($budget); $limit->budget()->associate($budget);
$limit->start_date = $data['start_date']->format('Y-m-d'); $limit->start_date = $data['start_date']->format('Y-m-d');
$limit->end_date = $data['end_date']->format('Y-m-d'); $limit->end_date = $data['end_date']->format('Y-m-d');
@@ -306,7 +294,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
$limit->transaction_currency_id = $currency->id; $limit->transaction_currency_id = $currency->id;
$limit->save(); $limit->save();
$noteText = (string) ($data['notes'] ?? ''); $noteText = (string) ($data['notes'] ?? '');
if ('' !== $noteText) { if ('' !== $noteText) {
$this->setNoteText($limit, $noteText); $this->setNoteText($limit, $noteText);
} }
@@ -320,13 +308,12 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
{ {
/** @var null|BudgetLimit */ /** @var null|BudgetLimit */
return $budget->budgetlimits() return $budget->budgetlimits()
->where('transaction_currency_id', $currency->id) ->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->first() ->where('end_date', $end->format('Y-m-d'))->first();
;
} }
#[\Override] #[Override]
public function setNoteText(BudgetLimit $budgetLimit, string $text): void public function setNoteText(BudgetLimit $budgetLimit, string $text): void
{ {
$dbNote = $budgetLimit->notes()->first(); $dbNote = $budgetLimit->notes()->first();
@@ -348,8 +335,8 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
*/ */
public function update(BudgetLimit $budgetLimit, array $data): BudgetLimit public function update(BudgetLimit $budgetLimit, array $data): BudgetLimit
{ {
$budgetLimit->amount = array_key_exists('amount', $data) ? $data['amount'] : $budgetLimit->amount; $budgetLimit->amount = array_key_exists('amount', $data) ? $data['amount'] : $budgetLimit->amount;
$budgetLimit->budget_id = array_key_exists('budget_id', $data) ? $data['budget_id'] : $budgetLimit->budget_id; $budgetLimit->budget_id = array_key_exists('budget_id', $data) ? $data['budget_id'] : $budgetLimit->budget_id;
if (array_key_exists('start', $data)) { if (array_key_exists('start', $data)) {
$budgetLimit->start_date = $data['start']->startOfDay(); $budgetLimit->start_date = $data['start']->startOfDay();
@@ -361,7 +348,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
} }
// if no currency has been provided, use the user's default currency: // if no currency has been provided, use the user's default currency:
$currency = null; $currency = null;
// update if relevant: // update if relevant:
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) { if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
@@ -373,7 +360,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
if (null === $currency) { if (null === $currency) {
$currency = $budgetLimit->transactionCurrency ?? app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $currency = $budgetLimit->transactionCurrency ?? app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
} }
$currency->enabled = true; $currency->enabled = true;
$currency->save(); $currency->save();
$budgetLimit->transaction_currency_id = $currency->id; $budgetLimit->transaction_currency_id = $currency->id;
@@ -390,29 +377,26 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $amount): ?BudgetLimit public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $amount): ?BudgetLimit
{ {
// count the limits: // count the limits:
$limits = $budget->budgetlimits() $limits = $budget->budgetlimits()
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00')) ->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00')) ->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
->count('budget_limits.*') ->count('budget_limits.*');
;
app('log')->debug(sprintf('Found %d budget limits.', $limits)); app('log')->debug(sprintf('Found %d budget limits.', $limits));
// there might be a budget limit for these dates: // there might be a budget limit for these dates:
/** @var null|BudgetLimit $limit */ /** @var null|BudgetLimit $limit */
$limit = $budget->budgetlimits() $limit = $budget->budgetlimits()
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00')) ->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00')) ->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
->first(['budget_limits.*']) ->first(['budget_limits.*']);
;
// if more than 1 limit found, delete the others: // if more than 1 limit found, delete the others:
if ($limits > 1 && null !== $limit) { if ($limits > 1 && null !== $limit) {
app('log')->debug(sprintf('Found more than 1, delete all except #%d', $limit->id)); app('log')->debug(sprintf('Found more than 1, delete all except #%d', $limit->id));
$budget->budgetlimits() $budget->budgetlimits()
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00')) ->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00')) ->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
->where('budget_limits.id', '!=', $limit->id)->delete() ->where('budget_limits.id', '!=', $limit->id)->delete();
;
} }
// delete if amount is zero. // delete if amount is zero.
@@ -434,7 +418,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup
} }
app('log')->debug('No existing budget limit, create a new one'); app('log')->debug('No existing budget limit, create a new one');
// or create one and return it. // or create one and return it.
$limit = new BudgetLimit(); $limit = new BudgetLimit();
$limit->budget()->associate($budget); $limit->budget()->associate($budget);
$limit->start_date = $start->startOfDay(); $limit->start_date = $start->startOfDay();
$limit->start_date_tz = $start->format('e'); $limit->start_date_tz = $start->format('e');

View File

@@ -63,8 +63,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$search->whereLike('name', sprintf('%%%s', $query)); $search->whereLike('name', sprintf('%%%s', $query));
} }
$search->orderBy('order', 'ASC') $search->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->where('active', true) ->orderBy('name', 'ASC')->where('active', true);
;
return $search->take($limit)->get(); return $search->take($limit)->get();
} }
@@ -76,8 +75,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$search->whereLike('name', sprintf('%s%%', $query)); $search->whereLike('name', sprintf('%s%%', $query));
} }
$search->orderBy('order', 'ASC') $search->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->where('active', true) ->orderBy('name', 'ASC')->where('active', true);
;
return $search->take($limit)->get(); return $search->take($limit)->get();
} }
@@ -85,7 +83,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
public function budgetedInPeriod(Carbon $start, Carbon $end): array public function budgetedInPeriod(Carbon $start, Carbon $end): array
{ {
app('log')->debug(sprintf('Now in budgetedInPeriod("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d'))); app('log')->debug(sprintf('Now in budgetedInPeriod("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d')));
$return = []; $return = [];
/** @var BudgetLimitRepository $limitRepository */ /** @var BudgetLimitRepository $limitRepository */
$limitRepository = app(BudgetLimitRepository::class); $limitRepository = app(BudgetLimitRepository::class);
@@ -102,9 +100,9 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
/** @var BudgetLimit $limit */ /** @var BudgetLimit $limit */
foreach ($limits as $limit) { foreach ($limits as $limit) {
app('log')->debug(sprintf('Budget limit #%d', $limit->id)); app('log')->debug(sprintf('Budget limit #%d', $limit->id));
$currency = $limit->transactionCurrency; $currency = $limit->transactionCurrency;
$rate = $converter->getCurrencyRate($currency, $defaultCurrency, $end); $rate = $converter->getCurrencyRate($currency, $defaultCurrency, $end);
$currencyCode = $currency->code; $currencyCode = $currency->code;
$return[$currencyCode] ??= [ $return[$currencyCode] ??= [
'currency_id' => (string) $currency->id, 'currency_id' => (string) $currency->id,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
@@ -159,10 +157,9 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
public function getActiveBudgets(): Collection public function getActiveBudgets(): Collection
{ {
return $this->user->budgets()->where('active', true) return $this->user->budgets()->where('active', true)
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('name', 'ASC') ->orderBy('name', 'ASC')
->get() ->get();
;
} }
/** /**
@@ -202,19 +199,19 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
public function budgetedInPeriodForBudget(Budget $budget, Carbon $start, Carbon $end): array public function budgetedInPeriodForBudget(Budget $budget, Carbon $start, Carbon $end): array
{ {
app('log')->debug(sprintf('Now in budgetedInPeriod(#%d, "%s", "%s")', $budget->id, $start->format('Y-m-d'), $end->format('Y-m-d'))); app('log')->debug(sprintf('Now in budgetedInPeriod(#%d, "%s", "%s")', $budget->id, $start->format('Y-m-d'), $end->format('Y-m-d')));
$return = []; $return = [];
/** @var BudgetLimitRepository $limitRepository */ /** @var BudgetLimitRepository $limitRepository */
$limitRepository = app(BudgetLimitRepository::class); $limitRepository = app(BudgetLimitRepository::class);
$limitRepository->setUser($this->user); $limitRepository->setUser($this->user);
app('log')->debug(sprintf('Budget #%d: "%s"', $budget->id, $budget->name)); app('log')->debug(sprintf('Budget #%d: "%s"', $budget->id, $budget->name));
$limits = $limitRepository->getBudgetLimits($budget, $start, $end); $limits = $limitRepository->getBudgetLimits($budget, $start, $end);
/** @var BudgetLimit $limit */ /** @var BudgetLimit $limit */
foreach ($limits as $limit) { foreach ($limits as $limit) {
app('log')->debug(sprintf('Budget limit #%d', $limit->id)); app('log')->debug(sprintf('Budget limit #%d', $limit->id));
$currency = $limit->transactionCurrency; $currency = $limit->transactionCurrency;
$return[$currency->id] ??= [ $return[$currency->id] ??= [
'id' => (string) $currency->id, 'id' => (string) $currency->id,
'name' => $currency->name, 'name' => $currency->name,
@@ -283,7 +280,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
{ {
app('log')->debug('Now in update()'); app('log')->debug('Now in update()');
$oldName = $budget->name; $oldName = $budget->name;
if (array_key_exists('name', $data)) { if (array_key_exists('name', $data)) {
$budget->name = $data['name']; $budget->name = $data['name'];
$this->updateRuleActions($oldName, $budget->name); $this->updateRuleActions($oldName, $budget->name);
@@ -298,7 +295,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$budget->save(); $budget->save();
// update or create auto-budget: // update or create auto-budget:
$autoBudget = $this->getAutoBudget($budget); $autoBudget = $this->getAutoBudget($budget);
// first things first: delete when no longer required: // first things first: delete when no longer required:
$autoBudgetType = array_key_exists('auto_budget_type', $data) ? $data['auto_budget_type'] : null; $autoBudgetType = array_key_exists('auto_budget_type', $data) ? $data['auto_budget_type'] : null;
@@ -324,11 +321,10 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
{ {
$types = ['set_budget']; $types = ['set_budget'];
$actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id') $actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id')
->where('rules.user_id', $this->user->id) ->where('rules.user_id', $this->user->id)
->whereIn('rule_actions.action_type', $types) ->whereIn('rule_actions.action_type', $types)
->where('rule_actions.action_value', $oldName) ->where('rule_actions.action_value', $oldName)
->get(['rule_actions.*']) ->get(['rule_actions.*']);
;
app('log')->debug(sprintf('Found %d actions to update.', $actions->count())); app('log')->debug(sprintf('Found %d actions to update.', $actions->count()));
/** @var RuleAction $action */ /** @var RuleAction $action */
@@ -343,11 +339,10 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
{ {
$types = ['budget_is']; $types = ['budget_is'];
$triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id') $triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rules.user_id', $this->user->id) ->where('rules.user_id', $this->user->id)
->whereIn('rule_triggers.trigger_type', $types) ->whereIn('rule_triggers.trigger_type', $types)
->where('rule_triggers.trigger_value', $oldName) ->where('rule_triggers.trigger_value', $oldName)
->get(['rule_triggers.*']) ->get(['rule_triggers.*']);
;
app('log')->debug(sprintf('Found %d triggers to update.', $triggers->count())); app('log')->debug(sprintf('Found %d triggers to update.', $triggers->count()));
/** @var RuleTrigger $trigger */ /** @var RuleTrigger $trigger */
@@ -391,7 +386,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$autoBudget = $this->getAutoBudget($budget); $autoBudget = $this->getAutoBudget($budget);
// grab default currency: // grab default currency:
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
if (null === $autoBudget) { if (null === $autoBudget) {
// at this point it's a blind assumption auto_budget_type is 1 or 2. // at this point it's a blind assumption auto_budget_type is 1 or 2.
@@ -471,8 +466,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
public function getBudgets(): Collection public function getBudgets(): Collection
{ {
return $this->user->budgets()->orderBy('order', 'ASC') return $this->user->budgets()->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->get() ->orderBy('name', 'ASC')->get();
;
} }
public function destroyAutoBudget(Budget $budget): void public function destroyAutoBudget(Budget $budget): void
@@ -530,7 +524,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
public function getAttachments(Budget $budget): Collection public function getAttachments(Budget $budget): Collection
{ {
$set = $budget->attachments()->get(); $set = $budget->attachments()->get();
$disk = Storage::disk('upload'); $disk = Storage::disk('upload');
@@ -556,9 +550,8 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
public function getInactiveBudgets(): Collection public function getInactiveBudgets(): Collection
{ {
return $this->user->budgets() return $this->user->budgets()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->where('active', 0)->get() ->orderBy('name', 'ASC')->where('active', 0)->get();
;
} }
public function getNoteText(Budget $budget): ?string public function getNoteText(Budget $budget): ?string
@@ -578,8 +571,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$search->whereLike('name', sprintf('%%%s%%', $query)); $search->whereLike('name', sprintf('%%%s%%', $query));
} }
$search->orderBy('order', 'ASC') $search->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->where('active', true) ->orderBy('name', 'ASC')->where('active', true);
;
return $search->take($limit)->get(); return $search->take($limit)->get();
} }
@@ -599,8 +591,8 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
// exclude specific liabilities // exclude specific liabilities
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities')); $subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
$selection = new Collection(); $selection = new Collection();
/** @var Account $account */ /** @var Account $account */
foreach ($subset as $account) { foreach ($subset as $account) {
@@ -611,20 +603,19 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
// start collecting: // start collecting:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user) $collector->setUser($this->user)
->setRange($start, $end) ->setRange($start, $end)
->excludeDestinationAccounts($selection) ->excludeDestinationAccounts($selection)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value]) ->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
->setBudgets($this->getActiveBudgets()) ->setBudgets($this->getActiveBudgets());
;
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'id' => (string) $currencyId, 'id' => (string) $currencyId,
'name' => $journal['currency_name'], 'name' => $journal['currency_name'],
'symbol' => $journal['currency_symbol'], 'symbol' => $journal['currency_symbol'],
@@ -635,9 +626,9 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount'])); $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount']));
// also do foreign amount: // also do foreign amount:
$foreignId = (int) $journal['foreign_currency_id']; $foreignId = (int) $journal['foreign_currency_id'];
if (0 !== $foreignId) { if (0 !== $foreignId) {
$array[$foreignId] ??= [ $array[$foreignId] ??= [
'id' => (string) $foreignId, 'id' => (string) $foreignId,
'name' => $journal['foreign_currency_name'], 'name' => $journal['foreign_currency_name'],
'symbol' => $journal['foreign_currency_symbol'], 'symbol' => $journal['foreign_currency_symbol'],
@@ -661,8 +652,8 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
// exclude specific liabilities // exclude specific liabilities
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities')); $subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
$selection = new Collection(); $selection = new Collection();
/** @var Account $account */ /** @var Account $account */
foreach ($subset as $account) { foreach ($subset as $account) {
@@ -673,20 +664,19 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
// start collecting: // start collecting:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user) $collector->setUser($this->user)
->setRange($start, $end) ->setRange($start, $end)
->excludeDestinationAccounts($selection) ->excludeDestinationAccounts($selection)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value]) ->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
->setBudget($budget) ->setBudget($budget);
;
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'id' => (string) $currencyId, 'id' => (string) $currencyId,
'name' => $journal['currency_name'], 'name' => $journal['currency_name'],
'symbol' => $journal['currency_symbol'], 'symbol' => $journal['currency_symbol'],
@@ -697,9 +687,9 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount'])); $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount']));
// also do foreign amount: // also do foreign amount:
$foreignId = (int) $journal['foreign_currency_id']; $foreignId = (int) $journal['foreign_currency_id'];
if (0 !== $foreignId) { if (0 !== $foreignId) {
$array[$foreignId] ??= [ $array[$foreignId] ??= [
'id' => (string) $foreignId, 'id' => (string) $foreignId,
'name' => $journal['foreign_currency_name'], 'name' => $journal['foreign_currency_name'],
'symbol' => $journal['foreign_currency_symbol'], 'symbol' => $journal['foreign_currency_symbol'],
@@ -721,7 +711,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
*/ */
public function store(array $data): Budget public function store(array $data): Budget
{ {
$order = $this->getMaxOrder(); $order = $this->getMaxOrder();
try { try {
$newBudget = Budget::create( $newBudget = Budget::create(
@@ -748,7 +738,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
if (!array_key_exists('auto_budget_type', $data) || !array_key_exists('auto_budget_amount', $data) || !array_key_exists('auto_budget_period', $data)) { if (!array_key_exists('auto_budget_type', $data) || !array_key_exists('auto_budget_amount', $data) || !array_key_exists('auto_budget_period', $data)) {
return $newBudget; return $newBudget;
} }
$type = $data['auto_budget_type']; $type = $data['auto_budget_type'];
if ('none' === $type) { if ('none' === $type) {
return $newBudget; return $newBudget;
} }
@@ -767,8 +757,8 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
} }
/** @var CurrencyRepositoryInterface $repos */ /** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class); $repos = app(CurrencyRepositoryInterface::class);
$currency = null; $currency = null;
if (array_key_exists('currency_id', $data)) { if (array_key_exists('currency_id', $data)) {
$currency = $repos->find((int) $data['currency_id']); $currency = $repos->find((int) $data['currency_id']);
} }
@@ -779,7 +769,7 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
} }
$autoBudget = new AutoBudget(); $autoBudget = new AutoBudget();
$autoBudget->budget()->associate($newBudget); $autoBudget->budget()->associate($newBudget);
$autoBudget->transaction_currency_id = $currency->id; $autoBudget->transaction_currency_id = $currency->id;
$autoBudget->auto_budget_type = $type; $autoBudget->auto_budget_type = $type;
@@ -788,11 +778,11 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
$autoBudget->save(); $autoBudget->save();
// create initial budget limit. // create initial budget limit.
$today = today(config('app.timezone')); $today = today(config('app.timezone'));
$start = app('navigation')->startOfPeriod($today, $autoBudget->period); $start = app('navigation')->startOfPeriod($today, $autoBudget->period);
$end = app('navigation')->endOfPeriod($start, $autoBudget->period); $end = app('navigation')->endOfPeriod($start, $autoBudget->period);
$limitRepos = app(BudgetLimitRepositoryInterface::class); $limitRepos = app(BudgetLimitRepositoryInterface::class);
$limitRepos->setUser($this->user); $limitRepos->setUser($this->user);
$limitRepos->store( $limitRepos->store(
[ [

View File

@@ -45,17 +45,17 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface, UserGroupInterf
$carbonFormat = app('navigation')->preferredCarbonFormat($start, $end); $carbonFormat = app('navigation')->preferredCarbonFormat($start, $end);
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end); $collector->setAccounts($accounts)->setRange($start, $end);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
$collector->withoutBudget(); $collector->withoutBudget();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$data = []; $data = [];
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$data[$currencyId] ??= [ $data[$currencyId] ??= [
'id' => 0, 'id' => 0,
@@ -68,7 +68,7 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface, UserGroupInterf
'currency_decimal_places' => $journal['currency_decimal_places'], 'currency_decimal_places' => $journal['currency_decimal_places'],
'entries' => [], 'entries' => [],
]; ];
$date = $journal['date']->format($carbonFormat); $date = $journal['date']->format($carbonFormat);
if (!array_key_exists($date, $data[$currencyId]['entries'])) { if (!array_key_exists($date, $data[$currencyId]['entries'])) {
$data[$currencyId]['entries'][$date] = '0'; $data[$currencyId]['entries'][$date] = '0';
@@ -82,7 +82,7 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface, UserGroupInterf
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {

View File

@@ -62,7 +62,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
++$count; ++$count;
app('log')->debug(sprintf('Found %d budget limits. Per day is %s, total is %s', $count, $perDay, $total)); app('log')->debug(sprintf('Found %d budget limits. Per day is %s, total is %s', $count, $perDay, $total));
} }
$avg = $total; $avg = $total;
if ($count > 0) { if ($count > 0) {
$avg = bcdiv($total, (string) $count); $avg = bcdiv($total, (string) $count);
} }
@@ -84,21 +84,21 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
// get all transactions: // get all transactions:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end); $collector->setAccounts($accounts)->setRange($start, $end);
$collector->setBudgets($budgets); $collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
// loop transactions: // loop transactions:
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
// prep data array for currency: // prep data array for currency:
$budgetId = (int) $journal['budget_id']; $budgetId = (int) $journal['budget_id'];
$budgetName = $journal['budget_name']; $budgetName = $journal['budget_name'];
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$key = sprintf('%d-%d', $budgetId, $currencyId); $key = sprintf('%d-%d', $budgetId, $currencyId);
$data[$key] ??= [ $data[$key] ??= [
'id' => $budgetId, 'id' => $budgetId,
'name' => sprintf('%s (%s)', $budgetName, $journal['currency_name']), 'name' => sprintf('%s (%s)', $budgetName, $journal['currency_name']),
'sum' => '0', 'sum' => '0',
@@ -136,13 +136,13 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setBudgets($this->getBudgets()); $collector->setBudgets($this->getBudgets());
} }
$collector->withBudgetInformation()->withAccountInformation()->withCategoryInformation(); $collector->withBudgetInformation()->withAccountInformation()->withCategoryInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$budgetId = (int) $journal['budget_id']; $budgetId = (int) $journal['budget_id'];
$budgetName = (string) $journal['budget_name']; $budgetName = (string) $journal['budget_name'];
// catch "no category" entries. // catch "no category" entries.
if (0 === $budgetId) { if (0 === $budgetId) {
@@ -150,7 +150,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
// info about the currency: // info about the currency:
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'budgets' => [], 'budgets' => [],
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -202,7 +202,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $budgets = null, ?Collection $budgets = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null
): array { ): array
{
Log::debug(sprintf('Start of %s.', __METHOD__)); Log::debug(sprintf('Start of %s.', __METHOD__));
// this collector excludes all transfers TO liabilities (which are also withdrawals) // this collector excludes all transfers TO liabilities (which are also withdrawals)
// because those expenses only become expenses once they move from the liability to the friend. // because those expenses only become expenses once they move from the liability to the friend.
@@ -210,8 +211,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities')); $subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
$selection = new Collection(); $selection = new Collection();
/** @var Account $account */ /** @var Account $account */
foreach ($subset as $account) { foreach ($subset as $account) {
@@ -221,12 +222,11 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user) $collector->setUser($this->user)
->setRange($start, $end) ->setRange($start, $end)
// ->excludeDestinationAccounts($selection) // ->excludeDestinationAccounts($selection)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value]) ->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
;
if (null !== $accounts) { if (null !== $accounts) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
@@ -239,7 +239,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setCurrency($currency); $collector->setCurrency($currency);
} }
$collector->setBudgets($budgets); $collector->setBudgets($budgets);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
// same but for transactions in the foreign currency: // same but for transactions in the foreign currency:
if (null !== $currency) { if (null !== $currency) {

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Category; namespace FireflyIII\Repositories\Category;
use Carbon\Carbon; use Carbon\Carbon;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\CategoryFactory; use FireflyIII\Factory\CategoryFactory;
use FireflyIII\Models\Attachment; use FireflyIII\Models\Attachment;
@@ -150,7 +151,7 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
public function store(array $data): Category public function store(array $data): Category
{ {
/** @var CategoryFactory $factory */ /** @var CategoryFactory $factory */
$factory = app(CategoryFactory::class); $factory = app(CategoryFactory::class);
$factory->setUser($this->user); $factory->setUser($this->user);
$category = $factory->findOrCreate(null, $data['name']); $category = $factory->findOrCreate(null, $data['name']);
@@ -176,7 +177,7 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
public function updateNotes(Category $category, string $notes): void public function updateNotes(Category $category, string $notes): void
{ {
$dbNote = $category->notes()->first(); $dbNote = $category->notes()->first();
if (null === $dbNote) { if (null === $dbNote) {
$dbNote = new Note(); $dbNote = new Note();
$dbNote->noteable()->associate($category); $dbNote->noteable()->associate($category);
@@ -222,10 +223,9 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
private function getFirstTransactionDate(Category $category): ?Carbon private function getFirstTransactionDate(Category $category): ?Carbon
{ {
// check transactions: // check transactions:
$query = $category->transactions() $query = $category->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'ASC') ->orderBy('transaction_journals.date', 'ASC');
;
$lastTransaction = $query->first(['transaction_journals.*']); $lastTransaction = $query->first(['transaction_journals.*']);
if (null !== $lastTransaction) { if (null !== $lastTransaction) {
@@ -237,7 +237,7 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
public function getAttachments(Category $category): Collection public function getAttachments(Category $category): Collection
{ {
$set = $category->attachments()->get(); $set = $category->attachments()->get();
$disk = Storage::disk('upload'); $disk = Storage::disk('upload');
@@ -271,7 +271,7 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function lastUseDate(Category $category, Collection $accounts): ?Carbon public function lastUseDate(Category $category, Collection $accounts): ?Carbon
{ {
@@ -297,7 +297,7 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
private function getLastJournalDate(Category $category, Collection $accounts): ?Carbon private function getLastJournalDate(Category $category, Collection $accounts): ?Carbon
{ {
$query = $category->transactionJournals()->orderBy('date', 'DESC'); $query = $category->transactionJournals()->orderBy('date', 'DESC');
if ($accounts->count() > 0) { if ($accounts->count() > 0) {
$query->leftJoin('transactions as t', 't.transaction_journal_id', '=', 'transaction_journals.id'); $query->leftJoin('transactions as t', 't.transaction_journal_id', '=', 'transaction_journals.id');
@@ -314,15 +314,14 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
private function getLastTransactionDate(Category $category, Collection $accounts): ?Carbon private function getLastTransactionDate(Category $category, Collection $accounts): ?Carbon
{ {
// check transactions: // check transactions:
$query = $category->transactions() $query = $category->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC');
;
if ($accounts->count() > 0) { if ($accounts->count() > 0) {
// filter journals: // filter journals:
$query->whereIn('transactions.account_id', $accounts->pluck('id')->toArray()); $query->whereIn('transactions.account_id', $accounts->pluck('id')->toArray());
@@ -347,7 +346,7 @@ class CategoryRepository implements CategoryRepositoryInterface, UserGroupInterf
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function update(Category $category, array $data): Category public function update(Category $category, array $data): Category
{ {

View File

@@ -52,12 +52,12 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'categories' => [], 'categories' => [],
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -74,12 +74,12 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
// add journal to array: // add journal to array:
// only a subset of the fields. // only a subset of the fields.
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
$array[$currencyId]['categories'][0]['transaction_journals'][$journalId] $array[$currencyId]['categories'][0]['transaction_journals'][$journalId]
= [ = [
'amount' => app('steam')->negative($journal['amount']), 'amount' => app('steam')->negative($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
]; ];
} }
return $array; return $array;
@@ -98,12 +98,12 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'categories' => [], 'categories' => [],
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -120,12 +120,12 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
]; ];
// add journal to array: // add journal to array:
// only a subset of the fields. // only a subset of the fields.
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
$array[$currencyId]['categories'][0]['transaction_journals'][$journalId] $array[$currencyId]['categories'][0]['transaction_journals'][$journalId]
= [ = [
'amount' => app('steam')->positive($journal['amount']), 'amount' => app('steam')->positive($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
]; ];
} }
return $array; return $array;
@@ -137,7 +137,7 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->withoutCategory(); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->withoutCategory();
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
@@ -161,12 +161,12 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -189,12 +189,12 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface, UserGroupIn
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],

View File

@@ -31,7 +31,6 @@ use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer; use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface; use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -64,13 +63,13 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setCategories($this->getCategories()); $collector->setCategories($this->getCategories());
} }
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation(); $collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$categoryId = (int) $journal['category_id']; $categoryId = (int) $journal['category_id'];
$categoryName = (string) $journal['category_name']; $categoryName = (string) $journal['category_name'];
// catch "no category" entries. // catch "no category" entries.
if (0 === $categoryId) { if (0 === $categoryId) {
@@ -78,7 +77,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
// info about the currency: // info about the currency:
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'categories' => [], 'categories' => [],
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -141,13 +140,13 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setCategories($this->getCategories()); $collector->setCategories($this->getCategories());
} }
$collector->withCategoryInformation()->withAccountInformation(); $collector->withCategoryInformation()->withAccountInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$categoryId = (int) $journal['category_id']; $categoryId = (int) $journal['category_id'];
$categoryName = (string) $journal['category_name']; $categoryName = (string) $journal['category_name'];
// catch "no category" entries. // catch "no category" entries.
if (0 === $categoryId) { if (0 === $categoryId) {
@@ -155,7 +154,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
// info about the currency: // info about the currency:
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'categories' => [], 'categories' => [],
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -194,8 +193,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::TRANSFER->value]) $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::TRANSFER->value])
->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts) ->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts);
;
if (null !== $categories && $categories->count() > 0) { if (null !== $categories && $categories->count() > 0) {
$collector->setCategories($categories); $collector->setCategories($categories);
} }
@@ -203,13 +201,13 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setCategories($this->getCategories()); $collector->setCategories($this->getCategories());
} }
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation(); $collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$categoryId = (int) $journal['category_id']; $categoryId = (int) $journal['category_id'];
$categoryName = (string) $journal['category_name']; $categoryName = (string) $journal['category_name'];
// catch "no category" entries. // catch "no category" entries.
if (0 === $categoryId) { if (0 === $categoryId) {
@@ -217,7 +215,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
// info about the currency: // info about the currency:
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'categories' => [], 'categories' => [],
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -257,8 +255,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::TRANSFER->value]) $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::TRANSFER->value])
->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts) ->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts);
;
if (null !== $categories && $categories->count() > 0) { if (null !== $categories && $categories->count() > 0) {
$collector->setCategories($categories); $collector->setCategories($categories);
} }
@@ -266,13 +263,13 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$collector->setCategories($this->getCategories()); $collector->setCategories($this->getCategories());
} }
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation(); $collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$categoryId = (int) $journal['category_id']; $categoryId = (int) $journal['category_id'];
$categoryName = (string) $journal['category_name']; $categoryName = (string) $journal['category_name'];
// catch "no category" entries. // catch "no category" entries.
if (0 === $categoryId) { if (0 === $categoryId) {
@@ -280,7 +277,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
} }
// info about the currency: // info about the currency:
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'categories' => [], 'categories' => [],
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -321,7 +318,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
@@ -344,10 +341,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end) $collector->setUser($this->user)->setRange($start, $end)
->setTypes([TransactionTypeEnum::DEPOSIT->value]) ->setTypes([TransactionTypeEnum::DEPOSIT->value]);
;
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
@@ -363,12 +359,12 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
foreach ($journals as $journal) { foreach ($journals as $journal) {
// Almost the same as in \FireflyIII\Repositories\Budget\OperationsRepository::sumExpenses // Almost the same as in \FireflyIII\Repositories\Budget\OperationsRepository::sumExpenses
$amount = '0'; $amount = '0';
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currencyName = $journal['currency_name']; $currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol']; $currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places']; $currencyDecimalPlaces = $journal['currency_decimal_places'];
if ($convertToNative) { if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal); $amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) { if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
@@ -393,7 +389,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$amount = $journal['amount']; $amount = $journal['amount'];
} }
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_name' => $currencyName, 'currency_name' => $currencyName,
@@ -415,8 +411,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end) $collector->setUser($this->user)->setRange($start, $end)
->setTypes([TransactionTypeEnum::TRANSFER->value]) ->setTypes([TransactionTypeEnum::TRANSFER->value]);
;
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
@@ -425,12 +420,12 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$categories = $this->getCategories(); $categories = $this->getCategories();
} }
$collector->setCategories($categories); $collector->setCategories($categories);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'sum' => '0', 'sum' => '0',
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],

View File

@@ -40,9 +40,9 @@ use FireflyIII\Services\Internal\Destroy\CurrencyDestroyService;
use FireflyIII\Services\Internal\Update\CurrencyUpdateService; use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface; use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Override;
/** /**
* Class CurrencyRepository. * Class CurrencyRepository.
@@ -60,12 +60,235 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
return null !== $result; return null !== $result;
} }
/**
* @throws FireflyException
*/
public function currencyInUseAt(TransactionCurrency $currency): ?string
{
app('log')->debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
$countJournals = $this->countJournals($currency);
if ($countJournals > 0) {
app('log')->info(sprintf('Count journals is %d, return true.', $countJournals));
return 'journals';
}
// is the only currency left
if (1 === $this->getAll()->count()) {
app('log')->info('Is the last currency in the system, return true. ');
return 'last_left';
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// second search using integer check.
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in bills:
$bills = Bill::where('transaction_currency_id', $currency->id)->count();
if ($bills > 0) {
app('log')->info(sprintf('Used in %d bills as currency, return true. ', $bills));
return 'bills';
}
// is being used in recurring transactions
$recurringAmount = RecurrenceTransaction::where('transaction_currency_id', $currency->id)->count();
$recurringForeign = RecurrenceTransaction::where('foreign_currency_id', $currency->id)->count();
if ($recurringAmount > 0 || $recurringForeign > 0) {
app('log')->info(sprintf('Used in %d recurring transactions as (foreign) currency id, return true. ', $recurringAmount + $recurringForeign));
return 'recurring';
}
// is being used in accounts (as integer)
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
->whereNull('accounts.deleted_at')
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count();
if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in available budgets
$availableBudgets = AvailableBudget::where('transaction_currency_id', $currency->id)->count();
if ($availableBudgets > 0) {
app('log')->info(sprintf('Used in %d available budgets as currency, return true. ', $availableBudgets));
return 'available_budgets';
}
// is being used in budget limits
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
if ($budgetLimit > 0) {
app('log')->info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit));
return 'budget_limits';
}
// is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) {
app('log')->info('Is the default currency of the user, return true.');
return 'current_default';
}
// is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) {
app('log')->info('Is the default currency of the user group, return true.');
return 'current_default';
}
app('log')->debug('Currency is not used, return false.');
return null;
}
private function countJournals(TransactionCurrency $currency): int
{
$count = $currency->transactions()->whereNull('deleted_at')->count() + $currency->transactionJournals()->whereNull('deleted_at')->count();
// also count foreign:
return $count + Transaction::where('foreign_currency_id', $currency->id)->count();
}
/**
* Returns ALL currencies, regardless of whether they are enabled or not.
*/
public function getAll(): Collection
{
$all = TransactionCurrency::orderBy('code', 'ASC')->get();
$local = $this->get();
return $all->map(static function (TransactionCurrency $current) use ($local) {
$hasId = $local->contains(static function (TransactionCurrency $entry) use ($current) {
return $entry->id === $current->id;
});
$isNative = $local->contains(static function (TransactionCurrency $entry) use ($current) {
return 1 === (int) $entry->pivot->group_default && $entry->id === $current->id;
});
$current->userGroupEnabled = $hasId;
$current->userGroupNative = $isNative;
return $current;
});
}
public function get(): Collection
{
$all = $this->userGroup->currencies()->orderBy('code', 'ASC')->withPivot(['group_default'])->get();
$all->map(static function (TransactionCurrency $current) { // @phpstan-ignore-line
$current->userGroupEnabled = true;
$current->userGroupNative = 1 === (int) $current->pivot->group_default;
return $current;
});
/** @var Collection */
return $all;
}
public function destroy(TransactionCurrency $currency): bool
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole($this->user, 'owner')) {
/** @var CurrencyDestroyService $service */
$service = app(CurrencyDestroyService::class);
$service->destroy($currency);
}
return true;
}
public function disable(TransactionCurrency $currency): void public function disable(TransactionCurrency $currency): void
{ {
$this->userGroup->currencies()->detach($currency->id); $this->userGroup->currencies()->detach($currency->id);
$currency->enabled = false; $currency->enabled = false;
$currency->save(); $currency->save();
} }
public function findByName(string $name): ?TransactionCurrency
{
return TransactionCurrency::where('name', $name)->first();
}
/**
* Find by object, ID or code. Returns user default or system default.
*
* @throws FireflyException
*/
public function findCurrency(?int $currencyId, ?string $currencyCode): TransactionCurrency
{
$result = $this->findCurrencyNull($currencyId, $currencyCode);
if (null === $result) {
app('log')->debug('Grabbing default currency for this user...');
/** @var null|TransactionCurrency $result */
$result = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
}
app('log')->debug(sprintf('Final result: %s', $result->code));
if (false === $result->enabled) {
app('log')->debug(sprintf('Also enabled currency %s', $result->code));
$this->enable($result);
}
return $result;
}
/**
* Find by object, ID or code. Returns NULL if nothing found.
*/
public function findCurrencyNull(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{
app('log')->debug('Now in findCurrencyNull()');
$result = $this->find((int) $currencyId);
if (null === $result) {
app('log')->debug(sprintf('Searching for currency with code %s...', $currencyCode));
$result = $this->findByCode((string) $currencyCode);
}
if (null !== $result && false === $result->enabled) {
app('log')->debug(sprintf('Also enabled currency %s', $result->code));
$this->enable($result);
}
return $result;
}
#[Override]
public function find(int $currencyId): ?TransactionCurrency
{
return TransactionCurrency::find($currencyId);
}
/**
* Find by currency code, return NULL if unfound.
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
}
public function enable(TransactionCurrency $currency): void public function enable(TransactionCurrency $currency): void
{ {
$this->userGroup->currencies()->syncWithoutDetaching([$currency->id]); $this->userGroup->currencies()->syncWithoutDetaching([$currency->id]);
@@ -73,6 +296,91 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
$currency->save(); $currency->save();
} }
/**
* Returns the complete set of transactions but needs
* no user object.
*/
public function getCompleteSet(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* Get currency exchange rate.
*/
public function getExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date): ?CurrencyExchangeRate
{
if ($fromCurrency->id === $toCurrency->id) {
$rate = new CurrencyExchangeRate();
$rate->rate = '1';
$rate->id = 0;
return $rate;
}
/** @var null|CurrencyExchangeRate $rate */
$rate = $this->user->currencyExchangeRates()
->where('from_currency_id', $fromCurrency->id)
->where('to_currency_id', $toCurrency->id)
->where('date', $date->format('Y-m-d'))->first();
if (null !== $rate) {
app('log')->debug(sprintf('Found cached exchange rate in database for %s to %s on %s', $fromCurrency->code, $toCurrency->code, $date->format('Y-m-d')));
return $rate;
}
return null;
}
public function isFallbackCurrency(TransactionCurrency $currency): bool
{
return $currency->code === config('firefly.default_currency', 'EUR');
}
public function searchCurrency(string $search, int $limit): Collection
{
$query = TransactionCurrency::where('enabled', true);
if ('' !== $search) {
$query->whereLike('name', sprintf('%%%s%%', $search));
}
return $query->take($limit)->get();
}
/**
* TODO must be a factory
*/
public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate
{
return CurrencyExchangeRate::create(
[
'user_id' => $this->user->id,
'user_group_id' => $this->user->user_group_id,
'from_currency_id' => $fromCurrency->id,
'to_currency_id' => $toCurrency->id,
'date' => $date,
'date_tz' => $date->format('e'),
'rate' => $rate,
]
);
}
/**
* @throws FireflyException
*/
public function store(array $data): TransactionCurrency
{
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
$result = $factory->create($data);
if (true === $data['enabled']) {
$this->userGroup->currencies()->attach($result->id);
}
return $result;
}
public function update(TransactionCurrency $currency, array $data): TransactionCurrency public function update(TransactionCurrency $currency, array $data): TransactionCurrency
{ {
app('log')->debug('Now in update()'); app('log')->debug('Now in update()');
@@ -111,33 +419,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
return $service->update($currency, $data); return $service->update($currency, $data);
} }
public function destroy(TransactionCurrency $currency): bool
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole($this->user, 'owner')) {
/** @var CurrencyDestroyService $service */
$service = app(CurrencyDestroyService::class);
$service->destroy($currency);
}
return true;
}
/**
* @throws FireflyException
*/
public function store(array $data): TransactionCurrency
{
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
$result = $factory->create($data);
if (true === $data['enabled']) {
$this->userGroup->currencies()->attach($result->id);
}
return $result;
}
public function makeDefault(TransactionCurrency $currency): void public function makeDefault(TransactionCurrency $currency): void
{ {
$current = app('amount')->getNativeCurrencyByUserGroup($this->userGroup); $current = app('amount')->getNativeCurrencyByUserGroup($this->userGroup);
@@ -153,230 +435,4 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
event(new UserGroupChangedDefaultCurrency($this->userGroup)); event(new UserGroupChangedDefaultCurrency($this->userGroup));
} }
} }
public function isFallbackCurrency(TransactionCurrency $currency): bool
{
return $currency->code === config('firefly.default_currency', 'EUR');
}
/**
* Returns ALL currencies, regardless of whether they are enabled or not.
*/
public function getAll(): Collection
{
$all = TransactionCurrency::orderBy('code', 'ASC')->get();
$local = $this->get();
return $all->map(static function (TransactionCurrency $current) use ($local) {
$hasId = $local->contains(static function (TransactionCurrency $entry) use ($current) {
return $entry->id === $current->id;
});
$isNative = $local->contains(static function (TransactionCurrency $entry) use ($current) {
return 1 === (int) $entry->pivot->group_default && $entry->id === $current->id;
});
$current->userGroupEnabled = $hasId;
$current->userGroupNative = $isNative;
return $current;
});
}
private function countJournals(TransactionCurrency $currency): int
{
$count = $currency->transactions()->whereNull('deleted_at')->count() + $currency->transactionJournals()->whereNull('deleted_at')->count();
// also count foreign:
return $count + Transaction::where('foreign_currency_id', $currency->id)->count();
}
/**
* @throws FireflyException
*/
public function currencyInUseAt(TransactionCurrency $currency): ?string
{
app('log')->debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
$countJournals = $this->countJournals($currency);
if ($countJournals > 0) {
app('log')->info(sprintf('Count journals is %d, return true.', $countJournals));
return 'journals';
}
// is the only currency left
if (1 === $this->getAll()->count()) {
app('log')->info('Is the last currency in the system, return true. ');
return 'last_left';
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// second search using integer check.
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in bills:
$bills = Bill::where('transaction_currency_id', $currency->id)->count();
if ($bills > 0) {
app('log')->info(sprintf('Used in %d bills as currency, return true. ', $bills));
return 'bills';
}
// is being used in recurring transactions
$recurringAmount = RecurrenceTransaction::where('transaction_currency_id', $currency->id)->count();
$recurringForeign = RecurrenceTransaction::where('foreign_currency_id', $currency->id)->count();
if ($recurringAmount > 0 || $recurringForeign > 0) {
app('log')->info(sprintf('Used in %d recurring transactions as (foreign) currency id, return true. ', $recurringAmount + $recurringForeign));
return 'recurring';
}
// is being used in accounts (as integer)
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
->whereNull('accounts.deleted_at')
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count()
;
if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in available budgets
$availableBudgets = AvailableBudget::where('transaction_currency_id', $currency->id)->count();
if ($availableBudgets > 0) {
app('log')->info(sprintf('Used in %d available budgets as currency, return true. ', $availableBudgets));
return 'available_budgets';
}
// is being used in budget limits
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
if ($budgetLimit > 0) {
app('log')->info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit));
return 'budget_limits';
}
// is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) {
app('log')->info('Is the default currency of the user, return true.');
return 'current_default';
}
// is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) {
app('log')->info('Is the default currency of the user group, return true.');
return 'current_default';
}
app('log')->debug('Currency is not used, return false.');
return null;
}
public function searchCurrency(string $search, int $limit): Collection
{
$query = TransactionCurrency::where('enabled', true);
if ('' !== $search) {
$query->whereLike('name', sprintf('%%%s%%', $search));
}
return $query->take($limit)->get();
}
#[\Override]
public function find(int $currencyId): ?TransactionCurrency
{
return TransactionCurrency::find($currencyId);
}
/**
* Find by currency code, return NULL if unfound.
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
}
/**
* Returns the complete set of transactions but needs
* no user object.
*/
public function getCompleteSet(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
public function get(): Collection
{
$all = $this->userGroup->currencies()->orderBy('code', 'ASC')->withPivot(['group_default'])->get();
$all->map(static function (TransactionCurrency $current) { // @phpstan-ignore-line
$current->userGroupEnabled = true;
$current->userGroupNative = 1 === (int) $current->pivot->group_default;
return $current;
});
/** @var Collection */
return $all;
}
/**
* Get currency exchange rate.
*/
public function getExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date): ?CurrencyExchangeRate
{
if ($fromCurrency->id === $toCurrency->id) {
$rate = new CurrencyExchangeRate();
$rate->rate = '1';
$rate->id = 0;
return $rate;
}
/** @var null|CurrencyExchangeRate $rate */
$rate = $this->user->currencyExchangeRates()
->where('from_currency_id', $fromCurrency->id)
->where('to_currency_id', $toCurrency->id)
->where('date', $date->format('Y-m-d'))->first()
;
if (null !== $rate) {
app('log')->debug(sprintf('Found cached exchange rate in database for %s to %s on %s', $fromCurrency->code, $toCurrency->code, $date->format('Y-m-d')));
return $rate;
}
return null;
}
/**
* TODO must be a factory
*/
public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate
{
return CurrencyExchangeRate::create(
[
'user_id' => $this->user->id,
'user_group_id' => $this->user->user_group_id,
'from_currency_id' => $fromCurrency->id,
'to_currency_id' => $toCurrency->id,
'date' => $date,
'date_tz' => $date->format('e'),
'rate' => $rate,
]
);
}
} }

View File

@@ -46,26 +46,24 @@ use Illuminate\Support\Collection;
*/ */
interface CurrencyRepositoryInterface interface CurrencyRepositoryInterface
{ {
public function find(int $currencyId): ?TransactionCurrency; /**
public function searchCurrency(string $search, int $limit): Collection; * @throws FireflyException
public function isFallbackCurrency(TransactionCurrency $currency): bool; */
public function getAll(): Collection; public function currencyInUse(TransactionCurrency $currency): bool;
public function store(array $data): TransactionCurrency;
public function makeDefault(TransactionCurrency $currency): void;
public function destroy(TransactionCurrency $currency): bool;
public function enable(TransactionCurrency $currency): void;
public function disable(TransactionCurrency $currency): void;
public function update(TransactionCurrency $currency, array $data): TransactionCurrency;
/**
* @throws FireflyException
*/
public function currencyInUse(TransactionCurrency $currency);
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
public function currencyInUseAt(TransactionCurrency $currency): ?string; public function currencyInUseAt(TransactionCurrency $currency): ?string;
public function destroy(TransactionCurrency $currency): bool;
public function disable(TransactionCurrency $currency): void;
public function enable(TransactionCurrency $currency): void;
public function find(int $currencyId): ?TransactionCurrency;
/** /**
* Find by currency code, return NULL if unfound. * Find by currency code, return NULL if unfound.
* *
@@ -73,6 +71,21 @@ interface CurrencyRepositoryInterface
*/ */
public function findByCode(string $currencyCode): ?TransactionCurrency; public function findByCode(string $currencyCode): ?TransactionCurrency;
public function findByName(string $name): ?TransactionCurrency;
public function findCurrency(?int $currencyId, ?string $currencyCode): TransactionCurrency;
public function findCurrencyNull(?int $currencyId, ?string $currencyCode): ?TransactionCurrency;
/**
* Get the user group's currencies.
*
* @return Collection<TransactionCurrency>
*/
public function get(): Collection;
public function getAll(): Collection;
/** /**
* Returns the complete set of transactions but needs * Returns the complete set of transactions but needs
* no user object. * no user object.
@@ -81,14 +94,6 @@ interface CurrencyRepositoryInterface
*/ */
public function getCompleteSet(): Collection; public function getCompleteSet(): Collection;
/**
* Get the user group's currencies.
*
* @return Collection<TransactionCurrency>
*/
public function get(): Collection;
/** /**
* Get currency exchange rate. * Get currency exchange rate.
* *
@@ -96,10 +101,20 @@ interface CurrencyRepositoryInterface
*/ */
public function getExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date): ?CurrencyExchangeRate; public function getExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date): ?CurrencyExchangeRate;
public function isFallbackCurrency(TransactionCurrency $currency): bool;
public function makeDefault(TransactionCurrency $currency): void;
public function searchCurrency(string $search, int $limit): Collection;
/** /**
* Set currency exchange rate. * Set currency exchange rate.
* *
* Used in download exchange rate cron job. Needs the user object! * Used in download exchange rate cron job. Needs the user object!
*/ */
public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate; public function setExchangeRate(TransactionCurrency $fromCurrency, TransactionCurrency $toCurrency, Carbon $date, float $rate): CurrencyExchangeRate;
public function store(array $data): TransactionCurrency;
public function update(TransactionCurrency $currency, array $data): TransactionCurrency;
} }

View File

@@ -30,24 +30,25 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Override;
class ExchangeRateRepository implements ExchangeRateRepositoryInterface, UserGroupInterface class ExchangeRateRepository implements ExchangeRateRepositoryInterface, UserGroupInterface
{ {
use UserGroupTrait; use UserGroupTrait;
#[\Override] #[Override]
public function deleteRate(CurrencyExchangeRate $rate): void public function deleteRate(CurrencyExchangeRate $rate): void
{ {
$this->userGroup->currencyExchangeRates()->where('id', $rate->id)->delete(); $this->userGroup->currencyExchangeRates()->where('id', $rate->id)->delete();
} }
#[\Override] #[Override]
public function getAll(): Collection public function getAll(): Collection
{ {
return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get(); return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get();
} }
#[\Override] #[Override]
public function getRates(TransactionCurrency $from, TransactionCurrency $to): Collection public function getRates(TransactionCurrency $from, TransactionCurrency $to): Collection
{ {
// orderBy('date', 'DESC')->toRawSql(); // orderBy('date', 'DESC')->toRawSql();
@@ -56,21 +57,18 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface, UserGro
->where(function (Builder $q1) use ($from, $to): void { ->where(function (Builder $q1) use ($from, $to): void {
$q1->where(function (Builder $q) use ($from, $to): void { $q1->where(function (Builder $q) use ($from, $to): void {
$q->where('from_currency_id', $from->id) $q->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id) ->where('to_currency_id', $to->id);
;
})->orWhere(function (Builder $q) use ($from, $to): void { })->orWhere(function (Builder $q) use ($from, $to): void {
$q->where('from_currency_id', $to->id) $q->where('from_currency_id', $to->id)
->where('to_currency_id', $from->id) ->where('to_currency_id', $from->id);
;
}); });
}) })
->orderBy('date', 'DESC') ->orderBy('date', 'DESC')
->get(['currency_exchange_rates.*']) ->get(['currency_exchange_rates.*']);
;
} }
#[\Override] #[Override]
public function getSpecificRateOnDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): ?CurrencyExchangeRate public function getSpecificRateOnDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): ?CurrencyExchangeRate
{ {
/** @var null|CurrencyExchangeRate */ /** @var null|CurrencyExchangeRate */
@@ -79,11 +77,10 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface, UserGro
->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', $date->format('Y-m-d')) ->where('date', $date->format('Y-m-d'))
->first() ->first();
;
} }
#[\Override] #[Override]
public function storeExchangeRate(TransactionCurrency $from, TransactionCurrency $to, string $rate, Carbon $date): CurrencyExchangeRate public function storeExchangeRate(TransactionCurrency $from, TransactionCurrency $to, string $rate, Carbon $date): CurrencyExchangeRate
{ {
$object = new CurrencyExchangeRate(); $object = new CurrencyExchangeRate();
@@ -99,7 +96,7 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface, UserGro
return $object; return $object;
} }
#[\Override] #[Override]
public function updateExchangeRate(CurrencyExchangeRate $object, string $rate, ?Carbon $date = null): CurrencyExchangeRate public function updateExchangeRate(CurrencyExchangeRate $object, string $rate, ?Carbon $date = null): CurrencyExchangeRate
{ {
$object->rate = $rate; $object->rate = $rate;

View File

@@ -47,10 +47,9 @@ class JournalAPIRepository implements JournalAPIRepositoryInterface, UserGroupIn
public function findTransaction(int $transactionId): ?Transaction public function findTransaction(int $transactionId): ?Transaction
{ {
return Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') return Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.user_id', $this->user->id) ->where('transaction_journals.user_id', $this->user->id)
->where('transactions.id', $transactionId) ->where('transactions.id', $transactionId)
->first(['transactions.*']) ->first(['transactions.*']);
;
} }
/** /**
@@ -60,7 +59,7 @@ class JournalAPIRepository implements JournalAPIRepositoryInterface, UserGroupIn
*/ */
public function getAttachments(TransactionJournal $journal): Collection public function getAttachments(TransactionJournal $journal): Collection
{ {
$set = $journal->attachments; $set = $journal->attachments;
$disk = Storage::disk('upload'); $disk = Storage::disk('upload');

View File

@@ -32,6 +32,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use stdClass;
/** /**
* Class JournalCLIRepository * Class JournalCLIRepository
@@ -46,10 +47,9 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
public function getAllJournals(array $types): Collection public function getAllJournals(array $types): Collection
{ {
return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereIn('transaction_types.type', $types) ->whereIn('transaction_types.type', $types)
->with(['user', 'transactionType', 'transactionCurrency', 'transactions', 'transactions.account']) ->with(['user', 'transactionType', 'transactionCurrency', 'transactions', 'transactions.account'])
->get(['transaction_journals.*']) ->get(['transaction_journals.*']);
;
} }
/** /**
@@ -57,7 +57,7 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
*/ */
public function getJournalBudgetId(TransactionJournal $journal): int public function getJournalBudgetId(TransactionJournal $journal): int
{ {
$budget = $journal->budgets()->first(); $budget = $journal->budgets()->first();
if (null !== $budget) { if (null !== $budget) {
return $budget->id; return $budget->id;
} }
@@ -77,7 +77,7 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
*/ */
public function getJournalCategoryId(TransactionJournal $journal): int public function getJournalCategoryId(TransactionJournal $journal): int
{ {
$category = $journal->categories()->first(); $category = $journal->categories()->first();
if (null !== $category) { if (null !== $category) {
return $category->id; return $category->id;
} }
@@ -129,7 +129,7 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
*/ */
public function getMetaField(TransactionJournal $journal, string $field): ?string public function getMetaField(TransactionJournal $journal, string $field): ?string
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty('journal-meta-updated'); $cache->addProperty('journal-meta-updated');
$cache->addProperty($journal->id); $cache->addProperty($journal->id);
$cache->addProperty($field); $cache->addProperty($field);
@@ -138,12 +138,12 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
return $cache->get(); return $cache->get();
} }
$entry = $journal->transactionJournalMeta()->where('name', $field)->first(); $entry = $journal->transactionJournalMeta()->where('name', $field)->first();
if (null === $entry) { if (null === $entry) {
return null; return null;
} }
$value = $entry->data; $value = $entry->data;
if (is_array($value)) { if (is_array($value)) {
$return = implode(',', $value); $return = implode(',', $value);
@@ -179,12 +179,11 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
public function getSplitJournals(): Collection public function getSplitJournals(): Collection
{ {
$query = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') $query = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->groupBy('transaction_journals.id') ->groupBy('transaction_journals.id');
;
$result = $query->get(['transaction_journals.id as id', DB::raw('count(transactions.id) as transaction_count')]); // @phpstan-ignore-line $result = $query->get(['transaction_journals.id as id', DB::raw('count(transactions.id) as transaction_count')]); // @phpstan-ignore-line
$journalIds = []; $journalIds = [];
/** @var \stdClass $row */ /** @var stdClass $row */
foreach ($result as $row) { foreach ($result as $row) {
if ((int) $row->transaction_count > 2) { if ((int) $row->transaction_count > 2) {
$journalIds[] = (int) $row->id; $journalIds[] = (int) $row->id;
@@ -193,8 +192,7 @@ class JournalCLIRepository implements JournalCLIRepositoryInterface, UserGroupIn
$journalIds = array_unique($journalIds); $journalIds = array_unique($journalIds);
return TransactionJournal::with(['transactions']) return TransactionJournal::with(['transactions'])
->whereIn('id', $journalIds)->get() ->whereIn('id', $journalIds)->get();
;
} }
/** /**

View File

@@ -67,8 +67,7 @@ class JournalRepository implements JournalRepositoryInterface, UserGroupInterfac
->transactionJournals() ->transactionJournals()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereIn('transaction_types.type', $types) ->whereIn('transaction_types.type', $types)
->get(['transaction_journals.*']) ->get(['transaction_journals.*']);
;
} }
/** /**
@@ -102,7 +101,7 @@ class JournalRepository implements JournalRepositoryInterface, UserGroupInterfac
*/ */
public function getJournalTotal(TransactionJournal $journal): string public function getJournalTotal(TransactionJournal $journal): string
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($journal->id); $cache->addProperty($journal->id);
$cache->addProperty('amount-positive'); $cache->addProperty('amount-positive');
if ($cache->has()) { if ($cache->has()) {
@@ -151,8 +150,7 @@ class JournalRepository implements JournalRepositoryInterface, UserGroupInterfac
return new Carbon($cache->get()); return new Carbon($cache->get());
} }
$entry = TransactionJournalMeta::where('transaction_journal_id', $journalId) $entry = TransactionJournalMeta::where('transaction_journal_id', $journalId)
->where('name', $field)->first() ->where('name', $field)->first();
;
if (null === $entry) { if (null === $entry) {
return null; return null;
} }
@@ -195,8 +193,7 @@ class JournalRepository implements JournalRepositoryInterface, UserGroupInterfac
public function searchJournalDescriptions(string $search, int $limit): Collection public function searchJournalDescriptions(string $search, int $limit): Collection
{ {
$query = $this->user->transactionJournals() $query = $this->user->transactionJournals()
->orderBy('date', 'DESC') ->orderBy('date', 'DESC');
;
if ('' !== $search) { if ('' !== $search) {
$query->whereLike('description', sprintf('%%%s%%', $search)); $query->whereLike('description', sprintf('%%%s%%', $search));
} }

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\LinkType; namespace FireflyIII\Repositories\LinkType;
use Exception;
use FireflyIII\Events\DestroyedTransactionLink; use FireflyIII\Events\DestroyedTransactionLink;
use FireflyIII\Models\LinkType; use FireflyIII\Models\LinkType;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
@@ -71,7 +72,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroyLink(TransactionJournalLink $link): bool public function destroyLink(TransactionJournalLink $link): bool
{ {
@@ -116,13 +117,12 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
public function getJournalLinks(?LinkType $linkType = null): Collection public function getJournalLinks(?LinkType $linkType = null): Collection
{ {
$query = TransactionJournalLink::with(['source', 'destination']) $query = TransactionJournalLink::with(['source', 'destination'])
->leftJoin('transaction_journals as source_journals', 'journal_links.source_id', '=', 'source_journals.id') ->leftJoin('transaction_journals as source_journals', 'journal_links.source_id', '=', 'source_journals.id')
->leftJoin('transaction_journals as dest_journals', 'journal_links.destination_id', '=', 'dest_journals.id') ->leftJoin('transaction_journals as dest_journals', 'journal_links.destination_id', '=', 'dest_journals.id')
->where('source_journals.user_id', $this->user->id) ->where('source_journals.user_id', $this->user->id)
->where('dest_journals.user_id', $this->user->id) ->where('dest_journals.user_id', $this->user->id)
->whereNull('source_journals.deleted_at') ->whereNull('source_journals.deleted_at')
->whereNull('dest_journals.deleted_at') ->whereNull('dest_journals.deleted_at');
;
if (null !== $linkType) { if (null !== $linkType) {
$query->where('journal_links.link_type_id', $linkType->id); $query->where('journal_links.link_type_id', $linkType->id);
@@ -172,7 +172,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
/** /**
* Store link between two journals. * Store link between two journals.
* *
* @throws \Exception * @throws Exception
*/ */
public function storeLink(array $information, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink public function storeLink(array $information, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
{ {
@@ -192,7 +192,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
return $existing; return $existing;
} }
$link = new TransactionJournalLink(); $link = new TransactionJournalLink();
$link->linkType()->associate($linkType); $link->linkType()->associate($linkType);
if ('inward' === $information['direction']) { if ('inward' === $information['direction']) {
app('log')->debug(sprintf('Link type is inwards ("%s"), so %d is source and %d is destination.', $linkType->inward, $inward->id, $outward->id)); app('log')->debug(sprintf('Link type is inwards ("%s"), so %d is source and %d is destination.', $linkType->inward, $inward->id, $outward->id));
@@ -233,13 +233,12 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
{ {
return TransactionJournalLink::where('link_type_id', $linkType->id) return TransactionJournalLink::where('link_type_id', $linkType->id)
->where('source_id', $inward->id) ->where('source_id', $inward->id)
->where('destination_id', $outward->id)->first() ->where('destination_id', $outward->id)->first();
;
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
private function setNoteText(TransactionJournalLink $link, string $text): void private function setNoteText(TransactionJournalLink $link, string $text): void
{ {
@@ -281,7 +280,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
/** /**
* Update an existing transaction journal link. * Update an existing transaction journal link.
* *
* @throws \Exception * @throws Exception
*/ */
public function updateLink(TransactionJournalLink $journalLink, array $data): TransactionJournalLink public function updateLink(TransactionJournalLink $journalLink, array $data): TransactionJournalLink
{ {
@@ -297,7 +296,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
$journalLink->refresh(); $journalLink->refresh();
} }
$journalLink->link_type_id = null === $data['link_type_id'] ? $journalLink->link_type_id : $data['link_type_id']; $journalLink->link_type_id = null === $data['link_type_id'] ? $journalLink->link_type_id : $data['link_type_id'];
$journalLink->save(); $journalLink->save();
if (array_key_exists('notes', $data) && null !== $data['notes']) { if (array_key_exists('notes', $data) && null !== $data['notes']) {
$this->setNoteText($journalLink, $data['notes']); $this->setNoteText($journalLink, $data['notes']);

View File

@@ -53,10 +53,9 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface, UserGroup
public function get(): Collection public function get(): Collection
{ {
return $this->user->objectGroups() return $this->user->objectGroups()
->with(['piggyBanks', 'bills']) ->with(['piggyBanks', 'bills'])
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('title', 'ASC')->get() ->orderBy('title', 'ASC')->get();
;
} }
public function deleteEmpty(): void public function deleteEmpty(): void
@@ -149,18 +148,16 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface, UserGroup
if ($newOrder > $oldOrder) { if ($newOrder > $oldOrder) {
$this->user->objectGroups()->where('object_groups.order', '<=', $newOrder)->where('object_groups.order', '>', $oldOrder) $this->user->objectGroups()->where('object_groups.order', '<=', $newOrder)->where('object_groups.order', '>', $oldOrder)
->where('object_groups.id', '!=', $objectGroup->id) ->where('object_groups.id', '!=', $objectGroup->id)
->decrement('object_groups.order') ->decrement('object_groups.order');
;
$objectGroup->order = $newOrder; $objectGroup->order = $newOrder;
$objectGroup->save(); $objectGroup->save();
} }
if ($newOrder < $oldOrder) { if ($newOrder < $oldOrder) {
$this->user->objectGroups()->where('object_groups.order', '>=', $newOrder)->where('object_groups.order', '<', $oldOrder) $this->user->objectGroups()->where('object_groups.order', '>=', $newOrder)->where('object_groups.order', '<', $oldOrder)
->where('object_groups.id', '!=', $objectGroup->id) ->where('object_groups.id', '!=', $objectGroup->id)
->increment('object_groups.order') ->increment('object_groups.order');
;
$objectGroup->order = $newOrder; $objectGroup->order = $newOrder;
$objectGroup->save(); $objectGroup->save();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PiggyBank; namespace FireflyIII\Repositories\PiggyBank;
use Exception;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount; use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\PiggyBankFactory; use FireflyIII\Factory\PiggyBankFactory;
@@ -68,9 +69,9 @@ trait ModifiesPiggyBanks
$pivot->native_current_amount = null; $pivot->native_current_amount = null;
// also update native_current_amount. // also update native_current_amount.
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $userCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
if ($userCurrency->id !== $piggyBank->transaction_currency_id) { if ($userCurrency->id !== $piggyBank->transaction_currency_id) {
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true); $converter->setIgnoreSettings(true);
$pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $pivot->current_amount); $pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $pivot->current_amount);
} }
@@ -91,9 +92,9 @@ trait ModifiesPiggyBanks
$pivot->native_current_amount = null; $pivot->native_current_amount = null;
// also update native_current_amount. // also update native_current_amount.
$userCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $userCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
if ($userCurrency->id !== $piggyBank->transaction_currency_id) { if ($userCurrency->id !== $piggyBank->transaction_currency_id) {
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true); $converter->setIgnoreSettings(true);
$pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $pivot->current_amount); $pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $pivot->current_amount);
} }
@@ -125,8 +126,8 @@ trait ModifiesPiggyBanks
Log::debug(sprintf('Maximum amount: %s', $maxAmount)); Log::debug(sprintf('Maximum amount: %s', $maxAmount));
} }
$compare = bccomp($amount, $maxAmount); $compare = bccomp($amount, $maxAmount);
$result = $compare <= 0; $result = $compare <= 0;
Log::debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true))); Log::debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true)));
@@ -141,7 +142,7 @@ trait ModifiesPiggyBanks
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroy(PiggyBank $piggyBank): bool public function destroy(PiggyBank $piggyBank): bool
{ {
@@ -160,11 +161,11 @@ trait ModifiesPiggyBanks
public function setCurrentAmount(PiggyBank $piggyBank, string $amount): PiggyBank public function setCurrentAmount(PiggyBank $piggyBank, string $amount): PiggyBank
{ {
$repetition = $this->getRepetition($piggyBank); $repetition = $this->getRepetition($piggyBank);
if (null === $repetition) { if (null === $repetition) {
return $piggyBank; return $piggyBank;
} }
$max = $piggyBank->target_amount; $max = $piggyBank->target_amount;
if (1 === bccomp($amount, $max) && 0 !== bccomp($piggyBank->target_amount, '0')) { if (1 === bccomp($amount, $max) && 0 !== bccomp($piggyBank->target_amount, '0')) {
$amount = $max; $amount = $max;
} }
@@ -207,14 +208,14 @@ trait ModifiesPiggyBanks
public function update(PiggyBank $piggyBank, array $data): PiggyBank public function update(PiggyBank $piggyBank, array $data): PiggyBank
{ {
$piggyBank = $this->updateProperties($piggyBank, $data); $piggyBank = $this->updateProperties($piggyBank, $data);
if (array_key_exists('notes', $data)) { if (array_key_exists('notes', $data)) {
$this->updateNote($piggyBank, (string) $data['notes']); $this->updateNote($piggyBank, (string) $data['notes']);
} }
// update the order of the piggy bank: // update the order of the piggy bank:
$oldOrder = $piggyBank->order; $oldOrder = $piggyBank->order;
$newOrder = (int) ($data['order'] ?? $oldOrder); $newOrder = (int) ($data['order'] ?? $oldOrder);
if ($oldOrder !== $newOrder) { if ($oldOrder !== $newOrder) {
$this->setOrder($piggyBank, $newOrder); $this->setOrder($piggyBank, $newOrder);
} }
@@ -307,7 +308,7 @@ trait ModifiesPiggyBanks
return; return;
} }
$dbNote = $piggyBank->notes()->first(); $dbNote = $piggyBank->notes()->first();
if (null === $dbNote) { if (null === $dbNote) {
$dbNote = new Note(); $dbNote = new Note();
$dbNote->noteable()->associate($piggyBank); $dbNote->noteable()->associate($piggyBank);
@@ -318,16 +319,15 @@ trait ModifiesPiggyBanks
public function setOrder(PiggyBank $piggyBank, int $newOrder): bool public function setOrder(PiggyBank $piggyBank, int $newOrder): bool
{ {
$oldOrder = $piggyBank->order; $oldOrder = $piggyBank->order;
// Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder)); // Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
if ($newOrder > $oldOrder) { if ($newOrder > $oldOrder) {
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder) ->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id) ->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->decrement('piggy_banks.order') ->distinct()->decrement('piggy_banks.order');
;
$piggyBank->order = $newOrder; $piggyBank->order = $newOrder;
Log::debug(sprintf('[1] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder)); Log::debug(sprintf('[1] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
@@ -336,12 +336,11 @@ trait ModifiesPiggyBanks
return true; return true;
} }
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder) ->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id) ->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->increment('piggy_banks.order') ->distinct()->increment('piggy_banks.order');
;
$piggyBank->order = $newOrder; $piggyBank->order = $newOrder;
Log::debug(sprintf('[2] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder)); Log::debug(sprintf('[2] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
@@ -362,7 +361,7 @@ trait ModifiesPiggyBanks
} }
// if this account contains less than the amount, remove the current amount, update the amount and continue. // if this account contains less than the amount, remove the current amount, update the amount and continue.
$this->removeAmount($piggyBank, $account, $current); $this->removeAmount($piggyBank, $account, $current);
$amount = bcsub($amount, $current); $amount = bcsub($amount, $current);
} }
} }
} }

View File

@@ -41,6 +41,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Override;
/** /**
* Class PiggyBankRepository. * Class PiggyBankRepository.
@@ -56,10 +57,9 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
Log::channel('audit')->info('Delete all piggy banks through destroyAll'); Log::channel('audit')->info('Delete all piggy banks through destroyAll');
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->delete() ->delete();
;
} }
public function findPiggyBank(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank public function findPiggyBank(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank
@@ -90,10 +90,9 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
public function find(int $piggyBankId): ?PiggyBank public function find(int $piggyBankId): ?PiggyBank
{ {
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']) ->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
;
} }
/** /**
@@ -102,15 +101,14 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
public function findByName(string $name): ?PiggyBank public function findByName(string $name): ?PiggyBank
{ {
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->where('piggy_banks.name', $name)->first(['piggy_banks.*']) ->where('piggy_banks.name', $name)->first(['piggy_banks.*']);
;
} }
public function getAttachments(PiggyBank $piggyBank): Collection public function getAttachments(PiggyBank $piggyBank): Collection
{ {
$set = $piggyBank->attachments()->get(); $set = $piggyBank->attachments()->get();
$disk = Storage::disk('upload'); $disk = Storage::disk('upload');
@@ -157,15 +155,15 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
{ {
app('log')->debug(sprintf('Now in getExactAmount(%d, %d)', $piggyBank->id, $journal->id)); app('log')->debug(sprintf('Now in getExactAmount(%d, %d)', $piggyBank->id, $journal->id));
$operator = null; $operator = null;
$currency = null; $currency = null;
/** @var JournalRepositoryInterface $journalRepost */ /** @var JournalRepositoryInterface $journalRepost */
$journalRepost = app(JournalRepositoryInterface::class); $journalRepost = app(JournalRepositoryInterface::class);
$journalRepost->setUser($this->user); $journalRepost->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);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
@@ -173,11 +171,11 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
app('log')->debug(sprintf('Piggy bank #%d currency is %s', $piggyBank->id, $piggyBank->transactionCurrency->code)); app('log')->debug(sprintf('Piggy bank #%d currency is %s', $piggyBank->id, $piggyBank->transactionCurrency->code));
/** @var Transaction $source */ /** @var Transaction $source */
$source = $journal->transactions()->with(['account'])->where('amount', '<', 0)->first(); $source = $journal->transactions()->with(['account'])->where('amount', '<', 0)->first();
/** @var Transaction $destination */ /** @var Transaction $destination */
$destination = $journal->transactions()->with(['account'])->where('amount', '>', 0)->first(); $destination = $journal->transactions()->with(['account'])->where('amount', '>', 0)->first();
$hits = 0; $hits = 0;
foreach ($piggyBank->accounts as $account) { foreach ($piggyBank->accounts as $account) {
// matches source, which means amount will be removed from piggy: // matches source, which means amount will be removed from piggy:
@@ -209,7 +207,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
} }
// currency of the account + the piggy bank currency are almost the same. // currency of the account + the piggy bank currency are almost the same.
// which amount from the transaction matches? // which amount from the transaction matches?
$amount = null; $amount = null;
if ((int) $source->transaction_currency_id === $currency->id) { if ((int) $source->transaction_currency_id === $currency->id) {
app('log')->debug('Use normal amount'); app('log')->debug('Use normal amount');
$amount = app('steam')->{$operator}($source->amount); // @phpstan-ignore-line $amount = app('steam')->{$operator}($source->amount); // @phpstan-ignore-line
@@ -225,9 +223,9 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
} }
app('log')->debug(sprintf('The currency is %s and the amount is %s', $currency->code, $amount)); app('log')->debug(sprintf('The currency is %s and the amount is %s', $currency->code, $amount));
$currentAmount = $this->getCurrentAmount($piggyBank); $currentAmount = $this->getCurrentAmount($piggyBank);
$room = bcsub($piggyBank->target_amount, $currentAmount); $room = bcsub($piggyBank->target_amount, $currentAmount);
$compare = bcmul($currentAmount, '-1'); $compare = bcmul($currentAmount, '-1');
if (0 === bccomp($piggyBank->target_amount, '0')) { if (0 === bccomp($piggyBank->target_amount, '0')) {
// amount is zero? then the "room" is positive amount of we wish to add or remove. // amount is zero? then the "room" is positive amount of we wish to add or remove.
@@ -308,15 +306,14 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
public function getPiggyBanks(): Collection public function getPiggyBanks(): Collection
{ {
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->with( ->with(
[ [
'objectGroups', 'objectGroups',
] ]
) )
->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']) ->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']);
;
} }
public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition
@@ -382,24 +379,23 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
return $balance; return $balance;
} }
#[\Override] #[Override]
public function purgeAll(): void public function purgeAll(): void
{ {
PiggyBank::withTrashed() PiggyBank::withTrashed()
->whereNotNull('piggy_banks.deleted_at') ->whereNotNull('piggy_banks.deleted_at')
->leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') ->leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->with( ->with(
[ [
'objectGroups', 'objectGroups',
] ]
) )
->delete() ->delete();
;
} }
#[\Override] #[Override]
public function resetOrder(): void public function resetOrder(): void
{ {
$factory = new PiggyBankFactory(); $factory = new PiggyBankFactory();
@@ -410,21 +406,19 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
public function searchPiggyBank(string $query, int $limit): Collection public function searchPiggyBank(string $query, int $limit): Collection
{ {
$search = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') $search = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id) ->where('accounts.user_id', $this->user->id)
->with( ->with(
[ [
'objectGroups', 'objectGroups',
] ]
) )
->orderBy('piggy_banks.order', 'ASC')->distinct() ->orderBy('piggy_banks.order', 'ASC')->distinct();
;
if ('' !== $query) { if ('' !== $query) {
$search->whereLike('piggy_banks.name', sprintf('%%%s%%', $query)); $search->whereLike('piggy_banks.name', sprintf('%%%s%%', $query));
} }
$search->orderBy('piggy_banks.order', 'ASC') $search->orderBy('piggy_banks.order', 'ASC')
->orderBy('piggy_banks.name', 'ASC') ->orderBy('piggy_banks.name', 'ASC');
;
return $search->take($limit)->get(['piggy_banks.*']); return $search->take($limit)->get(['piggy_banks.*']);
} }

View File

@@ -45,7 +45,6 @@ use FireflyIII\Support\Repositories\Recurring\CalculateXOccurrencesSince;
use FireflyIII\Support\Repositories\Recurring\FiltersWeekends; use FireflyIII\Support\Repositories\Recurring\FiltersWeekends;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface; use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -68,9 +67,9 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
// if not, loop set and try to read the recurrence_date. If it matches start or end, return it as well. // if not, loop set and try to read the recurrence_date. If it matches start or end, return it as well.
$set $set
= TransactionJournalMeta::where(static function (Builder $q1) use ($recurrence): void { = TransactionJournalMeta::where(static function (Builder $q1) use ($recurrence): void {
$q1->where('name', 'recurrence_id'); $q1->where('name', 'recurrence_id');
$q1->where('data', json_encode((string) $recurrence->id)); $q1->where('data', json_encode((string) $recurrence->id));
})->get(['journal_meta.transaction_journal_id']); })->get(['journal_meta.transaction_journal_id']);
// there are X journals made for this recurrence. Any of them meant for today? // there are X journals made for this recurrence. Any of them meant for today?
foreach ($set as $journalMeta) { foreach ($set as $journalMeta) {
@@ -80,9 +79,8 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
$q2->where('name', 'recurrence_date'); $q2->where('name', 'recurrence_date');
$q2->where('data', json_encode($string)); $q2->where('data', json_encode($string));
}) })
->where('transaction_journal_id', $journalMeta->transaction_journal_id) ->where('transaction_journal_id', $journalMeta->transaction_journal_id)
->count() ->count();
;
if ($count > 0) { if ($count > 0) {
app('log')->debug(sprintf('Looks like journal #%d was already created', $journalMeta->transaction_journal_id)); app('log')->debug(sprintf('Looks like journal #%d was already created', $journalMeta->transaction_journal_id));
@@ -99,12 +97,11 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
public function get(): Collection public function get(): Collection
{ {
return $this->user->recurrences() return $this->user->recurrences()
->with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions']) ->with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('transaction_type_id', 'ASC') ->orderBy('transaction_type_id', 'ASC')
->orderBy('title', 'ASC') ->orderBy('title', 'ASC')
->get() ->get();
;
} }
/** /**
@@ -130,10 +127,9 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
{ {
// grab ALL recurring transactions: // grab ALL recurring transactions:
return Recurrence::with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions']) return Recurrence::with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('title', 'ASC') ->orderBy('title', 'ASC')
->get() ->get();
;
} }
public function getBillId(RecurrenceTransaction $recTransaction): ?int public function getBillId(RecurrenceTransaction $recTransaction): ?int
@@ -208,11 +204,10 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
{ {
Log::debug(sprintf('Now in getJournalCount(#%d, "%s", "%s")', $recurrence->id, $start?->format('Y-m-d H:i:s'), $end?->format('Y-m-d H:i:s'))); Log::debug(sprintf('Now in getJournalCount(#%d, "%s", "%s")', $recurrence->id, $start?->format('Y-m-d H:i:s'), $end?->format('Y-m-d H:i:s')));
$query = TransactionJournal::leftJoin('journal_meta', 'journal_meta.transaction_journal_id', '=', 'transaction_journals.id') $query = TransactionJournal::leftJoin('journal_meta', 'journal_meta.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.user_id', $recurrence->user_id) ->where('transaction_journals.user_id', $recurrence->user_id)
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->where('journal_meta.name', 'recurrence_id') ->where('journal_meta.name', 'recurrence_id')
->where('journal_meta.data', '"'.$recurrence->id.'"') ->where('journal_meta.data', '"' . $recurrence->id . '"');
;
if (null !== $start) { if (null !== $start) {
$query->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')); $query->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'));
} }
@@ -231,11 +226,10 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
public function getJournalIds(Recurrence $recurrence): array public function getJournalIds(Recurrence $recurrence): array
{ {
return TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id') return TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
->where('transaction_journals.user_id', $this->user->id) ->where('transaction_journals.user_id', $this->user->id)
->where('journal_meta.name', '=', 'recurrence_id') ->where('journal_meta.name', '=', 'recurrence_id')
->where('journal_meta.data', '=', json_encode((string) $recurrence->id)) ->where('journal_meta.data', '=', json_encode((string) $recurrence->id))
->get(['journal_meta.transaction_journal_id'])->pluck('transaction_journal_id')->toArray() ->get(['journal_meta.transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
;
} }
/** /**
@@ -283,24 +277,22 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
public function getTransactionPaginator(Recurrence $recurrence, int $page, int $pageSize): LengthAwarePaginator public function getTransactionPaginator(Recurrence $recurrence, int $page, int $pageSize): LengthAwarePaginator
{ {
$journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id') $journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id) ->where('transaction_journals.user_id', $this->user->id)
->where('name', 'recurrence_id') ->where('name', 'recurrence_id')
->where('data', json_encode((string) $recurrence->id)) ->where('data', json_encode((string) $recurrence->id))
->get()->pluck('transaction_journal_id')->toArray() ->get()->pluck('transaction_journal_id')->toArray();
;
$search = []; $search = [];
foreach ($journalMeta as $journalId) { foreach ($journalMeta as $journalId) {
$search[] = (int) $journalId; $search[] = (int) $journalId;
} }
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($recurrence->user); $collector->setUser($recurrence->user);
$collector->withCategoryInformation()->withBudgetInformation()->setLimit($pageSize)->setPage($page) $collector->withCategoryInformation()->withBudgetInformation()->setLimit($pageSize)->setPage($page)
->withAccountInformation() ->withAccountInformation();
;
$collector->setJournalIds($search); $collector->setJournalIds($search);
return $collector->getPaginatedGroups(); return $collector->getPaginatedGroups();
@@ -309,12 +301,11 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
public function getTransactions(Recurrence $recurrence): Collection public function getTransactions(Recurrence $recurrence): Collection
{ {
$journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id') $journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id) ->where('transaction_journals.user_id', $this->user->id)
->where('name', 'recurrence_id') ->where('name', 'recurrence_id')
->where('data', json_encode((string) $recurrence->id)) ->where('data', json_encode((string) $recurrence->id))
->get()->pluck('transaction_journal_id')->toArray() ->get()->pluck('transaction_journal_id')->toArray();
;
$search = []; $search = [];
foreach ($journalMeta as $journalId) { foreach ($journalMeta as $journalId) {
@@ -325,7 +316,7 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
} }
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($recurrence->user); $collector->setUser($recurrence->user);
$collector->withCategoryInformation()->withBudgetInformation()->withAccountInformation(); $collector->withCategoryInformation()->withBudgetInformation()->withAccountInformation();
@@ -468,21 +459,21 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
); );
} }
if ('ndom' === $repetition->repetition_type) { if ('ndom' === $repetition->repetition_type) {
$parts = explode(',', $repetition->repetition_moment); $parts = explode(',', $repetition->repetition_moment);
// first part is number of week, second is weekday. // first part is number of week, second is weekday.
$dayOfWeek = trans(sprintf('config.dow_%s', $parts[1]), [], $language); $dayOfWeek = trans(sprintf('config.dow_%s', $parts[1]), [], $language);
return (string) trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $parts[0]], $language); return (string) trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $parts[0]], $language);
} }
if ('yearly' === $repetition->repetition_type) { if ('yearly' === $repetition->repetition_type) {
$today = today(config('app.timezone'))->endOfYear(); $today = today(config('app.timezone'))->endOfYear();
$repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment); $repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment);
if (null === $repDate) { if (null === $repDate) {
$repDate = clone $today; $repDate = clone $today;
} }
$diffInYears = (int) $today->diffInYears($repDate, true); $diffInYears = (int) $today->diffInYears($repDate, true);
$repDate->addYears($diffInYears); // technically not necessary. $repDate->addYears($diffInYears); // technically not necessary.
$string = $repDate->isoFormat((string) trans('config.month_and_day_no_year_js')); $string = $repDate->isoFormat((string) trans('config.month_and_day_no_year_js'));
return (string) trans('firefly.recurring_yearly', ['date' => $string], $language); return (string) trans('firefly.recurring_yearly', ['date' => $string], $language);
} }
@@ -497,8 +488,7 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
$search->whereLike('recurrences.title', sprintf('%%%s%%', $query)); $search->whereLike('recurrences.title', sprintf('%%%s%%', $query));
} }
$search $search
->orderBy('recurrences.title', 'ASC') ->orderBy('recurrences.title', 'ASC');
;
return $search->take($limit)->get(['id', 'title', 'description']); return $search->take($limit)->get(['id', 'title', 'description']);
} }
@@ -544,7 +534,7 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
$occurrences = []; $occurrences = [];
$mutator = clone $start; $mutator = clone $start;
$mutator->startOfDay(); $mutator->startOfDay();
$skipMod = $repetition->repetition_skip + 1; $skipMod = $repetition->repetition_skip + 1;
app('log')->debug(sprintf('Calculating occurrences for rep type "%s"', $repetition->repetition_type)); app('log')->debug(sprintf('Calculating occurrences for rep type "%s"', $repetition->repetition_type));
app('log')->debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d'))); app('log')->debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d')));

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Rule; namespace FireflyIII\Repositories\Rule;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -42,7 +43,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
use UserGroupTrait; use UserGroupTrait;
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroy(Rule $rule): bool public function destroy(Rule $rule): bool
{ {
@@ -111,7 +112,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
{ {
$count = $rule->ruleTriggers()->count(); $count = $rule->ruleTriggers()->count();
if (0 === $count) { if (0 === $count) {
throw new FireflyException('Rules should have more than zero triggers, rule #'.$rule->id.' has none!'); throw new FireflyException('Rules should have more than zero triggers, rule #' . $rule->id . ' has none!');
} }
return $rule->ruleTriggers()->where('trigger_type', 'user_action')->first()->trigger_value; return $rule->ruleTriggers()->where('trigger_type', 'user_action')->first()->trigger_value;
@@ -141,7 +142,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
if ('user_action' === $trigger->trigger_type) { if ('user_action' === $trigger->trigger_type) {
continue; continue;
} }
$triggerType = $trigger->trigger_type; $triggerType = $trigger->trigger_type;
if (str_starts_with($trigger->trigger_type, '-')) { if (str_starts_with($trigger->trigger_type, '-')) {
$triggerType = substr($trigger->trigger_type, 1); $triggerType = substr($trigger->trigger_type, 1);
} }
@@ -160,14 +161,13 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
public function getStoreRules(): Collection public function getStoreRules(): Collection
{ {
$collection = $this->user->rules() $collection = $this->user->rules()
->leftJoin('rule_groups', 'rule_groups.id', '=', 'rules.rule_group_id') ->leftJoin('rule_groups', 'rule_groups.id', '=', 'rules.rule_group_id')
->where('rules.active', true) ->where('rules.active', true)
->where('rule_groups.active', true) ->where('rule_groups.active', true)
->orderBy('rule_groups.order', 'ASC') ->orderBy('rule_groups.order', 'ASC')
->orderBy('rules.order', 'ASC') ->orderBy('rules.order', 'ASC')
->orderBy('rules.id', 'ASC') ->orderBy('rules.id', 'ASC')
->with(['ruleGroup', 'ruleTriggers'])->get(['rules.*']) ->with(['ruleGroup', 'ruleTriggers'])->get(['rules.*']);
;
$filtered = new Collection(); $filtered = new Collection();
/** @var Rule $rule */ /** @var Rule $rule */
@@ -186,14 +186,13 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
public function getUpdateRules(): Collection public function getUpdateRules(): Collection
{ {
$collection = $this->user->rules() $collection = $this->user->rules()
->leftJoin('rule_groups', 'rule_groups.id', '=', 'rules.rule_group_id') ->leftJoin('rule_groups', 'rule_groups.id', '=', 'rules.rule_group_id')
->where('rules.active', true) ->where('rules.active', true)
->where('rule_groups.active', true) ->where('rule_groups.active', true)
->orderBy('rule_groups.order', 'ASC') ->orderBy('rule_groups.order', 'ASC')
->orderBy('rules.order', 'ASC') ->orderBy('rules.order', 'ASC')
->orderBy('rules.id', 'ASC') ->orderBy('rules.id', 'ASC')
->with(['ruleGroup', 'ruleTriggers'])->get() ->with(['ruleGroup', 'ruleTriggers'])->get();
;
$filtered = new Collection(); $filtered = new Collection();
/** @var Rule $rule */ /** @var Rule $rule */
@@ -216,8 +215,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
$search->whereLike('rules.title', sprintf('%%%s%%', $query)); $search->whereLike('rules.title', sprintf('%%%s%%', $query));
} }
$search->orderBy('rules.order', 'ASC') $search->orderBy('rules.order', 'ASC')
->orderBy('rules.title', 'ASC') ->orderBy('rules.title', 'ASC');
;
return $search->take($limit)->get(['id', 'title', 'description']); return $search->take($limit)->get(['id', 'title', 'description']);
} }
@@ -227,7 +225,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
*/ */
public function store(array $data): Rule public function store(array $data): Rule
{ {
$ruleGroup = null; $ruleGroup = null;
if (array_key_exists('rule_group_id', $data)) { if (array_key_exists('rule_group_id', $data)) {
$ruleGroup = $this->user->ruleGroups()->find($data['rule_group_id']); $ruleGroup = $this->user->ruleGroups()->find($data['rule_group_id']);
} }
@@ -241,7 +239,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
/** @var RuleGroup $ruleGroup */ /** @var RuleGroup $ruleGroup */
// start by creating a new rule: // start by creating a new rule:
$rule = new Rule(); $rule = new Rule();
$rule->user()->associate($this->user); $rule->user()->associate($this->user);
$rule->userGroup()->associate($this->user->userGroup); $rule->userGroup()->associate($this->user->userGroup);
@@ -285,7 +283,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
private function setRuleTrigger(string $moment, Rule $rule): void private function setRuleTrigger(string $moment, Rule $rule): void
{ {
/** @var null|RuleTrigger $trigger */ /** @var null|RuleTrigger $trigger */
$trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first(); $trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first();
if (null !== $trigger) { if (null !== $trigger) {
$trigger->trigger_value = $moment; $trigger->trigger_value = $moment;
$trigger->save(); $trigger->save();
@@ -313,20 +311,19 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
public function setOrder(Rule $rule, int $newOrder): void public function setOrder(Rule $rule, int $newOrder): void
{ {
$oldOrder = $rule->order; $oldOrder = $rule->order;
$groupId = $rule->rule_group_id; $groupId = $rule->rule_group_id;
$maxOrder = $this->maxOrder($rule->ruleGroup); $maxOrder = $this->maxOrder($rule->ruleGroup);
$newOrder = $newOrder > $maxOrder ? $maxOrder + 1 : $newOrder; $newOrder = $newOrder > $maxOrder ? $maxOrder + 1 : $newOrder;
app('log')->debug(sprintf('New order will be %d', $newOrder)); app('log')->debug(sprintf('New order will be %d', $newOrder));
if ($newOrder > $oldOrder) { if ($newOrder > $oldOrder) {
$this->user->rules() $this->user->rules()
->where('rules.rule_group_id', $groupId) ->where('rules.rule_group_id', $groupId)
->where('rules.order', '<=', $newOrder) ->where('rules.order', '<=', $newOrder)
->where('rules.order', '>', $oldOrder) ->where('rules.order', '>', $oldOrder)
->where('rules.id', '!=', $rule->id) ->where('rules.id', '!=', $rule->id)
->decrement('rules.order') ->decrement('rules.order');
;
$rule->order = $newOrder; $rule->order = $newOrder;
app('log')->debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder)); app('log')->debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
$rule->save(); $rule->save();
@@ -335,12 +332,11 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
} }
$this->user->rules() $this->user->rules()
->where('rules.rule_group_id', $groupId) ->where('rules.rule_group_id', $groupId)
->where('rules.order', '>=', $newOrder) ->where('rules.order', '>=', $newOrder)
->where('rules.order', '<', $oldOrder) ->where('rules.order', '<', $oldOrder)
->where('rules.id', '!=', $rule->id) ->where('rules.id', '!=', $rule->id)
->increment('rules.order') ->increment('rules.order');
;
$rule->order = $newOrder; $rule->order = $newOrder;
app('log')->debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder)); app('log')->debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
$rule->save(); $rule->save();
@@ -365,7 +361,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
// empty the value in case the rule needs no context // empty the value in case the rule needs no context
// TODO create a helper to automatically return these. // TODO create a helper to automatically return these.
$needTrue = [ $needTrue = [
'reconciled', 'reconciled',
'has_attachments', 'has_attachments',
'has_any_category', 'has_any_category',
@@ -392,7 +388,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
$value = ''; $value = '';
} }
$triggerValues = [ $triggerValues = [
'action' => $type, 'action' => $type,
'value' => $value, 'value' => $value,
'stop_processing' => $stopProcessing, 'stop_processing' => $stopProcessing,
@@ -406,7 +402,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
public function storeTrigger(Rule $rule, array $values): RuleTrigger public function storeTrigger(Rule $rule, array $values): RuleTrigger
{ {
$ruleTrigger = new RuleTrigger(); $ruleTrigger = new RuleTrigger();
$ruleTrigger->rule()->associate($rule); $ruleTrigger->rule()->associate($rule);
$ruleTrigger->order = $values['order']; $ruleTrigger->order = $values['order'];
$ruleTrigger->active = $values['active']; $ruleTrigger->active = $values['active'];
@@ -439,7 +435,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
public function storeAction(Rule $rule, array $values): RuleAction public function storeAction(Rule $rule, array $values): RuleAction
{ {
$ruleAction = new RuleAction(); $ruleAction = new RuleAction();
$ruleAction->rule()->associate($rule); $ruleAction->rule()->associate($rule);
$ruleAction->order = $values['order']; $ruleAction->order = $values['order'];
$ruleAction->active = $values['active']; $ruleAction->active = $values['active'];
@@ -469,7 +465,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
} }
$rule->save(); $rule->save();
$rule->refresh(); $rule->refresh();
$group = $rule->ruleGroup; $group = $rule->ruleGroup;
// update the order: // update the order:
$this->resetRuleOrder($group); $this->resetRuleOrder($group);
if (array_key_exists('order', $data)) { if (array_key_exists('order', $data)) {

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\RuleGroup; namespace FireflyIII\Repositories\RuleGroup;
use Exception;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
@@ -47,8 +48,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('title', 'ASC') ->orderBy('title', 'ASC')
->get(['rule_groups.id']) ->get(['rule_groups.id']);
;
$index = 1; $index = 1;
/** @var RuleGroup $ruleGroup */ /** @var RuleGroup $ruleGroup */
@@ -72,7 +72,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroy(RuleGroup $ruleGroup, ?RuleGroup $moveTo): bool public function destroy(RuleGroup $ruleGroup, ?RuleGroup $moveTo): bool
{ {
@@ -105,8 +105,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
->whereNull('deleted_at') ->whereNull('deleted_at')
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('title', 'DESC') ->orderBy('title', 'DESC')
->get() ->get();
;
$count = 1; $count = 1;
/** @var RuleGroup $entry */ /** @var RuleGroup $entry */
@@ -128,11 +127,10 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
public function resetRuleOrder(RuleGroup $ruleGroup): bool public function resetRuleOrder(RuleGroup $ruleGroup): bool
{ {
$set = $ruleGroup->rules() $set = $ruleGroup->rules()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('title', 'DESC') ->orderBy('title', 'DESC')
->orderBy('updated_at', 'DESC') ->orderBy('updated_at', 'DESC')
->get(['rules.*']) ->get(['rules.*']);
;
$count = 1; $count = 1;
/** @var Rule $entry */ /** @var Rule $entry */
@@ -154,11 +152,10 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
private function resetRuleActionOrder(Rule $rule): void private function resetRuleActionOrder(Rule $rule): void
{ {
$actions = $rule->ruleActions() $actions = $rule->ruleActions()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('action_type', 'ASC') ->orderBy('action_type', 'ASC')
->get() ->get();
;
$index = 1; $index = 1;
/** @var RuleAction $action */ /** @var RuleAction $action */
@@ -175,11 +172,10 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
private function resetRuleTriggerOrder(Rule $rule): void private function resetRuleTriggerOrder(Rule $rule): void
{ {
$triggers = $rule->ruleTriggers() $triggers = $rule->ruleTriggers()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('active', 'DESC') ->orderBy('active', 'DESC')
->orderBy('trigger_type', 'ASC') ->orderBy('trigger_type', 'ASC')
->get() ->get();
;
$index = 1; $index = 1;
/** @var RuleTrigger $trigger */ /** @var RuleTrigger $trigger */
@@ -226,51 +222,47 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
public function getActiveRules(RuleGroup $group): Collection public function getActiveRules(RuleGroup $group): Collection
{ {
return $group->rules() return $group->rules()
->where('rules.active', true) ->where('rules.active', true)
->get(['rules.*']) ->get(['rules.*']);
;
} }
public function getActiveStoreRules(RuleGroup $group): Collection public function getActiveStoreRules(RuleGroup $group): Collection
{ {
return $group->rules() return $group->rules()
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id') ->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rule_triggers.trigger_type', 'user_action') ->where('rule_triggers.trigger_type', 'user_action')
->where('rule_triggers.trigger_value', 'store-journal') ->where('rule_triggers.trigger_value', 'store-journal')
->where('rules.active', true) ->where('rules.active', true)
->get(['rules.*']) ->get(['rules.*']);
;
} }
public function getActiveUpdateRules(RuleGroup $group): Collection public function getActiveUpdateRules(RuleGroup $group): Collection
{ {
return $group->rules() return $group->rules()
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id') ->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rule_triggers.trigger_type', 'user_action') ->where('rule_triggers.trigger_type', 'user_action')
->where('rule_triggers.trigger_value', 'update-journal') ->where('rule_triggers.trigger_value', 'update-journal')
->where('rules.active', true) ->where('rules.active', true)
->get(['rules.*']) ->get(['rules.*']);
;
} }
public function getAllRuleGroupsWithRules(?string $filter): Collection public function getAllRuleGroupsWithRules(?string $filter): Collection
{ {
$groups = $this->user->ruleGroups() $groups = $this->user->ruleGroups()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->with( ->with(
[ // @phpstan-ignore-line [ // @phpstan-ignore-line
'rules' => static function (HasMany $query): void { 'rules' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC'); $query->orderBy('order', 'ASC');
}, },
'rules.ruleTriggers' => static function (HasMany $query): void { 'rules.ruleTriggers' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC'); $query->orderBy('order', 'ASC');
}, },
'rules.ruleActions' => static function (HasMany $query): void { 'rules.ruleActions' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC'); $query->orderBy('order', 'ASC');
}, },
] ]
)->get() )->get();
;
if (null === $filter) { if (null === $filter) {
return $groups; return $groups;
} }
@@ -311,22 +303,21 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
public function getRuleGroupsWithRules(?string $filter): Collection public function getRuleGroupsWithRules(?string $filter): Collection
{ {
$groups = $this->user->ruleGroups() $groups = $this->user->ruleGroups()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->where('active', true) ->where('active', true)
->with( ->with(
[ // @phpstan-ignore-line [ // @phpstan-ignore-line
'rules' => static function (HasMany $query): void { 'rules' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC'); $query->orderBy('order', 'ASC');
}, },
'rules.ruleTriggers' => static function (HasMany $query): void { 'rules.ruleTriggers' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC'); $query->orderBy('order', 'ASC');
}, },
'rules.ruleActions' => static function (HasMany $query): void { 'rules.ruleActions' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC'); $query->orderBy('order', 'ASC');
}, },
] ]
)->get() )->get();
;
if (null === $filter) { if (null === $filter) {
return $groups; return $groups;
} }
@@ -360,8 +351,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
public function getRules(RuleGroup $group): Collection public function getRules(RuleGroup $group): Collection
{ {
return $group->rules() return $group->rules()
->get(['rules.*']) ->get(['rules.*']);
;
} }
public function maxOrder(): int public function maxOrder(): int
@@ -376,8 +366,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
$search->whereLike('rule_groups.title', sprintf('%%%s%%', $query)); $search->whereLike('rule_groups.title', sprintf('%%%s%%', $query));
} }
$search->orderBy('rule_groups.order', 'ASC') $search->orderBy('rule_groups.order', 'ASC')
->orderBy('rule_groups.title', 'ASC') ->orderBy('rule_groups.title', 'ASC');
;
return $search->take($limit)->get(['id', 'title', 'description']); return $search->take($limit)->get(['id', 'title', 'description']);
} }
@@ -405,13 +394,12 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
public function setOrder(RuleGroup $ruleGroup, int $newOrder): void public function setOrder(RuleGroup $ruleGroup, int $newOrder): void
{ {
$oldOrder = $ruleGroup->order; $oldOrder = $ruleGroup->order;
if ($newOrder > $oldOrder) { if ($newOrder > $oldOrder) {
$this->user->ruleGroups()->where('rule_groups.order', '<=', $newOrder)->where('rule_groups.order', '>', $oldOrder) $this->user->ruleGroups()->where('rule_groups.order', '<=', $newOrder)->where('rule_groups.order', '>', $oldOrder)
->where('rule_groups.id', '!=', $ruleGroup->id) ->where('rule_groups.id', '!=', $ruleGroup->id)
->decrement('order') ->decrement('order');
;
$ruleGroup->order = $newOrder; $ruleGroup->order = $newOrder;
app('log')->debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder)); app('log')->debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save(); $ruleGroup->save();
@@ -420,9 +408,8 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
} }
$this->user->ruleGroups()->where('rule_groups.order', '>=', $newOrder)->where('rule_groups.order', '<', $oldOrder) $this->user->ruleGroups()->where('rule_groups.order', '>=', $newOrder)->where('rule_groups.order', '<', $oldOrder)
->where('rule_groups.id', '!=', $ruleGroup->id) ->where('rule_groups.id', '!=', $ruleGroup->id)
->increment('order') ->increment('order');
;
$ruleGroup->order = $newOrder; $ruleGroup->order = $newOrder;
app('log')->debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder)); app('log')->debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save(); $ruleGroup->save();

View File

@@ -47,9 +47,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $tags = null): array public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $tags = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
$tagIds = []; $tagIds = [];
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
@@ -66,7 +66,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$array = []; $array = [];
$listedJournals = []; $listedJournals = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'tags' => [], 'tags' => [],
'currency_id' => $currencyId, 'currency_id' => $currencyId,
@@ -78,9 +78,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
// may have multiple tags: // may have multiple tags:
foreach ($journal['tags'] as $tag) { foreach ($journal['tags'] as $tag) {
$tagId = (int) $tag['id']; $tagId = (int) $tag['id'];
$tagName = (string) $tag['name']; $tagName = (string) $tag['name'];
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
if (!in_array($tagId, $tagIds, true)) { if (!in_array($tagId, $tagIds, true)) {
continue; continue;
} }
@@ -89,7 +89,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
if (in_array($journalId, $listedJournals, true)) { if (in_array($journalId, $listedJournals, true)) {
continue; continue;
} }
$listedJournals[] = $journalId; $listedJournals[] = $journalId;
$array[$currencyId]['tags'][$tagId] ??= [ $array[$currencyId]['tags'][$tagId] ??= [
'id' => $tagId, 'id' => $tagId,
'name' => $tagName, 'name' => $tagName,
@@ -130,9 +130,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $tags = null): array public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $tags = null): array
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::DEPOSIT->value]); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::DEPOSIT->value]);
$tagIds = []; $tagIds = [];
if (null !== $accounts && $accounts->count() > 0) { if (null !== $accounts && $accounts->count() > 0) {
$collector->setAccounts($accounts); $collector->setAccounts($accounts);
} }
@@ -150,7 +150,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$listedJournals = []; $listedJournals = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'tags' => [], 'tags' => [],
'currency_id' => $currencyId, 'currency_id' => $currencyId,
@@ -162,9 +162,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
// may have multiple tags: // may have multiple tags:
foreach ($journal['tags'] as $tag) { foreach ($journal['tags'] as $tag) {
$tagId = (int) $tag['id']; $tagId = (int) $tag['id'];
$tagName = (string) $tag['name']; $tagName = (string) $tag['name'];
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
if (!in_array($tagId, $tagIds, true)) { if (!in_array($tagId, $tagIds, true)) {
continue; continue;
@@ -173,9 +173,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
if (in_array($journalId, $listedJournals, true)) { if (in_array($journalId, $listedJournals, true)) {
continue; continue;
} }
$listedJournals[] = $journalId; $listedJournals[] = $journalId;
$array[$currencyId]['tags'][$tagId] ??= [ $array[$currencyId]['tags'][$tagId] ??= [
'id' => $tagId, 'id' => $tagId,
'name' => $tagName, 'name' => $tagName,
'transaction_journals' => [], 'transaction_journals' => [],

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Tag; namespace FireflyIII\Repositories\Tag;
use Carbon\Carbon; use Carbon\Carbon;
use Exception;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Factory\TagFactory; use FireflyIII\Factory\TagFactory;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
@@ -51,7 +52,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroy(Tag $tag): bool public function destroy(Tag $tag): bool
{ {
@@ -119,7 +120,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
return $set->each( return $set->each(
static function (Attachment $attachment) use ($disk): void { // @phpstan-ignore-line static function (Attachment $attachment) use ($disk): void { // @phpstan-ignore-line
/** @var null|Note $note */ /** @var null|Note $note */
$note = $attachment->notes()->first(); $note = $attachment->notes()->first();
// only used in v1 view of tags // only used in v1 view of tags
$attachment->file_exists = $disk->exists($attachment->fileName()); $attachment->file_exists = $disk->exists($attachment->fileName());
$attachment->notes_text = null === $note ? '' : $note->text; $attachment->notes_text = null === $note ? '' : $note->text;
@@ -130,7 +131,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
public function getTagsInYear(?int $year): array public function getTagsInYear(?int $year): array
{ {
// get all tags in the year (if present): // get all tags in the year (if present):
$tagQuery = $this->user->tags()->with(['locations', 'attachments'])->orderBy('tags.tag'); $tagQuery = $this->user->tags()->with(['locations', 'attachments'])->orderBy('tags.tag');
// add date range (or not): // add date range (or not):
if (null === $year) { if (null === $year) {
@@ -140,7 +141,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
if (null !== $year) { if (null !== $year) {
app('log')->debug(sprintf('Get tags with year %s.', $year)); app('log')->debug(sprintf('Get tags with year %s.', $year));
$tagQuery->where('tags.date', '>=', $year.'-01-01 00:00:00')->where('tags.date', '<=', $year.'-12-31 23:59:59'); $tagQuery->where('tags.date', '>=', $year . '-01-01 00:00:00')->where('tags.date', '<=', $year . '-12-31 23:59:59');
} }
$collection = $tagQuery->get(); $collection = $tagQuery->get();
$return = []; $return = [];
@@ -235,13 +236,13 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
} }
$collector->setTag($tag)->withAccountInformation(); $collector->setTag($tag)->withAccountInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$sums = []; $sums = [];
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$found = false; $found = false;
/** @var array $localTag */ /** @var array $localTag */
foreach ($journal['tags'] as $localTag) { foreach ($journal['tags'] as $localTag) {
@@ -252,7 +253,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
if (false === $found) { if (false === $found) {
continue; continue;
} }
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$sums[$currencyId] ??= [ $sums[$currencyId] ??= [
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -266,14 +267,14 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
]; ];
// add amount to correct type: // add amount to correct type:
$amount = app('steam')->positive((string) $journal['amount']); $amount = app('steam')->positive((string) $journal['amount']);
$type = $journal['transaction_type_type']; $type = $journal['transaction_type_type'];
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
$amount = bcmul($amount, '-1'); $amount = bcmul($amount, '-1');
} }
$sums[$currencyId][$type] = bcadd($sums[$currencyId][$type], $amount); $sums[$currencyId][$type] = bcadd($sums[$currencyId][$type], $amount);
$foreignCurrencyId = $journal['foreign_currency_id']; $foreignCurrencyId = $journal['foreign_currency_id'];
if (null !== $foreignCurrencyId && 0 !== $foreignCurrencyId) { if (null !== $foreignCurrencyId && 0 !== $foreignCurrencyId) {
$sums[$foreignCurrencyId] ??= [ $sums[$foreignCurrencyId] ??= [
'currency_id' => $foreignCurrencyId, 'currency_id' => $foreignCurrencyId,
@@ -287,7 +288,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
TransactionTypeEnum::OPENING_BALANCE->value => '0', TransactionTypeEnum::OPENING_BALANCE->value => '0',
]; ];
// add foreign amount to correct type: // add foreign amount to correct type:
$amount = app('steam')->positive((string) $journal['foreign_amount']); $amount = app('steam')->positive((string) $journal['foreign_amount']);
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
$amount = bcmul($amount, '-1'); $amount = bcmul($amount, '-1');
} }
@@ -352,7 +353,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
// otherwise, update or create. // otherwise, update or create.
if (!(null === $data['latitude'] && null === $data['longitude'] && null === $data['zoom_level'])) { if (!(null === $data['latitude'] && null === $data['longitude'] && null === $data['zoom_level'])) {
$location = $this->getLocation($tag); $location = $this->getLocation($tag);
if (null === $location) { if (null === $location) {
$location = new Location(); $location = new Location();
$location->locatable()->associate($tag); $location->locatable()->associate($tag);

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\TransactionGroup; namespace FireflyIII\Repositories\TransactionGroup;
use Carbon\Carbon; use Carbon\Carbon;
use Exception;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\DuplicateTransactionException; use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
@@ -140,22 +141,21 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
{ {
$repository = app(AttachmentRepositoryInterface::class); $repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$journals = $group->transactionJournals->pluck('id')->toArray(); $journals = $group->transactionJournals->pluck('id')->toArray();
$set = Attachment::whereIn('attachable_id', $journals) $set = Attachment::whereIn('attachable_id', $journals)
->where('attachable_type', TransactionJournal::class) ->where('attachable_type', TransactionJournal::class)
->where('uploaded', true) ->where('uploaded', true)
->whereNull('deleted_at')->get() ->whereNull('deleted_at')->get();
;
$result = []; $result = [];
/** @var Attachment $attachment */ /** @var Attachment $attachment */
foreach ($set as $attachment) { foreach ($set as $attachment) {
$journalId = $attachment->attachable_id; $journalId = $attachment->attachable_id;
$result[$journalId] ??= []; $result[$journalId] ??= [];
$current = $attachment->toArray(); $current = $attachment->toArray();
$current['file_exists'] = true; $current['file_exists'] = true;
$current['notes'] = $repository->getNoteText($attachment); $current['notes'] = $repository->getNoteText($attachment);
// already determined that this attachable is a TransactionJournal. // already determined that this attachable is a TransactionJournal.
$current['journal_title'] = $attachment->attachable->description; $current['journal_title'] = $attachment->attachable->description;
$result[$journalId][] = $current; $result[$journalId][] = $current;
@@ -171,9 +171,8 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
{ {
/** @var null|Note $note */ /** @var null|Note $note */
$note = Note::where('noteable_id', $journalId) $note = Note::where('noteable_id', $journalId)
->where('noteable_type', TransactionJournal::class) ->where('noteable_type', TransactionJournal::class)
->first() ->first();
;
if (null === $note) { if (null === $note) {
return null; return null;
} }
@@ -194,14 +193,13 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
$q->orWhereIn('destination_id', $journals); $q->orWhereIn('destination_id', $journals);
} }
) )
->with(['source', 'destination', 'source.transactions']) ->with(['source', 'destination', 'source.transactions'])
->leftJoin('link_types', 'link_types.id', '=', 'journal_links.link_type_id') ->leftJoin('link_types', 'link_types.id', '=', 'journal_links.link_type_id')
->get(['journal_links.*', 'link_types.inward', 'link_types.outward', 'link_types.editable']) ->get(['journal_links.*', 'link_types.inward', 'link_types.outward', 'link_types.editable']);
;
/** @var TransactionJournalLink $entry */ /** @var TransactionJournalLink $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$journalId = in_array($entry->source_id, $journals, true) ? $entry->source_id : $entry->destination_id; $journalId = in_array($entry->source_id, $journals, true) ? $entry->source_id : $entry->destination_id;
$return[$journalId] ??= []; $return[$journalId] ??= [];
// phpstan: the editable field is provided by the query. // phpstan: the editable field is provided by the query.
@@ -265,10 +263,10 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
if (0 === bccomp('0', $transaction->foreign_amount)) { if (0 === bccomp('0', $transaction->foreign_amount)) {
return ''; return '';
} }
$currency = $transaction->foreignCurrency; $currency = $transaction->foreignCurrency;
$type = $journal->transactionType->type; $type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->foreign_amount); $amount = app('steam')->positive($transaction->foreign_amount);
$return = ''; $return = '';
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount)); $return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
} }
@@ -291,16 +289,15 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
/** /**
* Return object with all found meta field things as Carbon objects. * Return object with all found meta field things as Carbon objects.
* *
* @throws \Exception * @throws Exception
*/ */
public function getMetaDateFields(int $journalId, array $fields): NullArrayObject public function getMetaDateFields(int $journalId, array $fields): NullArrayObject
{ {
$query = DB::table('journal_meta') $query = DB::table('journal_meta')
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereIn('name', $fields) ->whereIn('name', $fields)
->whereNull('deleted_at') ->whereNull('deleted_at')
->get(['name', 'data']) ->get(['name', 'data']);
;
$return = []; $return = [];
foreach ($query as $row) { foreach ($query as $row) {
@@ -316,11 +313,10 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
public function getMetaFields(int $journalId, array $fields): NullArrayObject public function getMetaFields(int $journalId, array $fields): NullArrayObject
{ {
$query = DB::table('journal_meta') $query = DB::table('journal_meta')
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereIn('name', $fields) ->whereIn('name', $fields)
->whereNull('deleted_at') ->whereNull('deleted_at')
->get(['name', 'data']) ->get(['name', 'data']);
;
$return = []; $return = [];
foreach ($query as $row) { foreach ($query as $row) {
@@ -341,9 +337,8 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
$journals = $group->transactionJournals->pluck('id')->toArray(); $journals = $group->transactionJournals->pluck('id')->toArray();
$currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup); $currency = app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
$data = PiggyBankEvent::whereIn('transaction_journal_id', $journals) $data = PiggyBankEvent::whereIn('transaction_journal_id', $journals)
->with('piggyBank', 'piggyBank.account') ->with('piggyBank', 'piggyBank.account')
->get(['piggy_bank_events.*']) ->get(['piggy_bank_events.*']);
;
/** @var PiggyBankEvent $row */ /** @var PiggyBankEvent $row */
foreach ($data as $row) { foreach ($data as $row) {
@@ -351,14 +346,13 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
continue; continue;
} }
// get currency preference. // get currency preference.
$currencyPreference = AccountMeta::where('account_id', $row->piggyBank->account_id) $currencyPreference = AccountMeta::where('account_id', $row->piggyBank->account_id)
->where('name', 'currency_id') ->where('name', 'currency_id')
->first() ->first();
;
if (null !== $currencyPreference) { if (null !== $currencyPreference) {
$currency = TransactionCurrency::where('id', $currencyPreference->data)->first(); $currency = TransactionCurrency::where('id', $currencyPreference->data)->first();
} }
$journalId = $row->transaction_journal_id; $journalId = $row->transaction_journal_id;
$return[$journalId] ??= []; $return[$journalId] ??= [];
$return[$journalId][] = [ $return[$journalId][] = [
@@ -385,11 +379,10 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
public function getTags(int $journalId): array public function getTags(int $journalId): array
{ {
$result = DB::table('tag_transaction_journal') $result = DB::table('tag_transaction_journal')
->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id') ->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id')
->where('tag_transaction_journal.transaction_journal_id', $journalId) ->where('tag_transaction_journal.transaction_journal_id', $journalId)
->orderBy('tags.tag', 'ASC') ->orderBy('tags.tag', 'ASC')
->get(['tags.tag']) ->get(['tags.tag']);
;
return $result->pluck('tag')->toArray(); return $result->pluck('tag')->toArray();
} }

View File

@@ -42,7 +42,7 @@ class TransactionTypeRepository implements TransactionTypeRepositoryInterface
return $type; return $type;
} }
$typeString ??= TransactionTypeEnum::WITHDRAWAL->value; $typeString ??= TransactionTypeEnum::WITHDRAWAL->value;
$search = $this->findByType($typeString); $search = $this->findByType($typeString);
if (null === $search) { if (null === $search) {
$search = $this->findByType(TransactionTypeEnum::WITHDRAWAL->value); $search = $this->findByType(TransactionTypeEnum::WITHDRAWAL->value);
} }

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\User; namespace FireflyIII\Repositories\User;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\GroupMembership; use FireflyIII\Models\GroupMembership;
@@ -34,6 +35,7 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Override;
/** /**
* Class UserRepository. * Class UserRepository.
@@ -44,17 +46,17 @@ class UserRepository implements UserRepositoryInterface
* This updates the users email address and records some things so it can be confirmed or undone later. * This updates the users email address and records some things so it can be confirmed or undone later.
* The user is blocked until the change is confirmed. * The user is blocked until the change is confirmed.
* *
* @throws \Exception * @throws Exception
* *
* @see updateEmail * @see updateEmail
*/ */
public function changeEmail(User $user, string $newEmail): bool public function changeEmail(User $user, string $newEmail): bool
{ {
$oldEmail = $user->email; $oldEmail = $user->email;
// save old email as pref // save old email as pref
app('preferences')->setForUser($user, 'previous_email_latest', $oldEmail); app('preferences')->setForUser($user, 'previous_email_latest', $oldEmail);
app('preferences')->setForUser($user, 'previous_email_'.date('Y-m-d-H-i-s'), $oldEmail); app('preferences')->setForUser($user, 'previous_email_' . date('Y-m-d-H-i-s'), $oldEmail);
// set undo and confirm token: // set undo and confirm token:
app('preferences')->setForUser($user, 'email_change_undo_token', bin2hex(random_bytes(16))); app('preferences')->setForUser($user, 'email_change_undo_token', bin2hex(random_bytes(16)));
@@ -99,7 +101,7 @@ class UserRepository implements UserRepositoryInterface
} }
/** /**
* @throws \Exception * @throws Exception
*/ */
public function destroy(User $user): bool public function destroy(User $user): bool
{ {
@@ -171,7 +173,7 @@ class UserRepository implements UserRepositoryInterface
public function getRolesInGroup(User $user, int $groupId): array public function getRolesInGroup(User $user, int $groupId): array
{ {
/** @var null|UserGroup $group */ /** @var null|UserGroup $group */
$group = UserGroup::find($groupId); $group = UserGroup::find($groupId);
if (null === $group) { if (null === $group) {
throw new FireflyException(sprintf('Could not find group #%d', $groupId)); throw new FireflyException(sprintf('Could not find group #%d', $groupId));
} }
@@ -197,7 +199,7 @@ class UserRepository implements UserRepositoryInterface
*/ */
public function getUserData(User $user): array public function getUserData(User $user): array
{ {
$return = []; $return = [];
// two factor: // two factor:
$return['has_2fa'] = null !== $user->mfa_secret; $return['has_2fa'] = null !== $user->mfa_secret;
@@ -213,12 +215,11 @@ class UserRepository implements UserRepositoryInterface
$return['categories'] = $user->categories()->count(); $return['categories'] = $user->categories()->count();
$return['budgets'] = $user->budgets()->count(); $return['budgets'] = $user->budgets()->count();
$return['budgets_with_limits'] = BudgetLimit::distinct() $return['budgets_with_limits'] = BudgetLimit::distinct()
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('amount', '>', 0) ->where('amount', '>', 0)
->whereNull('budgets.deleted_at') ->whereNull('budgets.deleted_at')
->where('budgets.user_id', $user->id) ->where('budgets.user_id', $user->id)
->count('budget_limits.budget_id') ->count('budget_limits.budget_id');
;
$return['rule_groups'] = $user->ruleGroups()->count(); $return['rule_groups'] = $user->ruleGroups()->count();
$return['rules'] = $user->rules()->count(); $return['rules'] = $user->rules()->count();
$return['tags'] = $user->tags()->count(); $return['tags'] = $user->tags()->count();
@@ -226,7 +227,7 @@ class UserRepository implements UserRepositoryInterface
return $return; return $return;
} }
public function hasRole(null|Authenticatable|User $user, string $role): bool public function hasRole(null | Authenticatable | User $user, string $role): bool
{ {
if (null === $user) { if (null === $user) {
return false; return false;
@@ -243,7 +244,7 @@ class UserRepository implements UserRepositoryInterface
return false; return false;
} }
#[\Override] #[Override]
public function getUserGroups(User $user): Collection public function getUserGroups(User $user): Collection
{ {
$memberships = $user->groupMemberships()->get(); $memberships = $user->groupMemberships()->get();
@@ -255,7 +256,7 @@ class UserRepository implements UserRepositoryInterface
/** @var null|UserGroup $group */ /** @var null|UserGroup $group */
$group = $membership->userGroup()->first(); $group = $membership->userGroup()->first();
if (null !== $group) { if (null !== $group) {
$groupId = $group->id; $groupId = $group->id;
if (in_array($groupId, array_keys($set), true)) { if (in_array($groupId, array_keys($set), true)) {
continue; continue;
} }
@@ -267,14 +268,14 @@ class UserRepository implements UserRepositoryInterface
return $collection; return $collection;
} }
public function inviteUser(null|Authenticatable|User $user, string $email): InvitedUser public function inviteUser(null | Authenticatable | User $user, string $email): InvitedUser
{ {
if (!$user instanceof User) { if (!$user instanceof User) {
throw new FireflyException('User is not a User object.'); throw new FireflyException('User is not a User object.');
} }
$now = today(config('app.timezone')); $now = today(config('app.timezone'));
$now->addDays(2); $now->addDays(2);
$invitee = new InvitedUser(); $invitee = new InvitedUser();
$invitee->user()->associate($user); $invitee->user()->associate($user);
$invitee->invite_code = Str::random(64); $invitee->invite_code = Str::random(64);
$invitee->email = $email; $invitee->email = $email;
@@ -385,11 +386,11 @@ class UserRepository implements UserRepositoryInterface
if ('' === $newEmail) { if ('' === $newEmail) {
return true; return true;
} }
$oldEmail = $user->email; $oldEmail = $user->email;
// save old email as pref // save old email as pref
app('preferences')->setForUser($user, 'admin_previous_email_latest', $oldEmail); app('preferences')->setForUser($user, 'admin_previous_email_latest', $oldEmail);
app('preferences')->setForUser($user, 'admin_previous_email_'.date('Y-m-d-H-i-s'), $oldEmail); app('preferences')->setForUser($user, 'admin_previous_email_' . date('Y-m-d-H-i-s'), $oldEmail);
$user->email = $newEmail; $user->email = $newEmail;
$user->save(); $user->save();

View File

@@ -106,9 +106,9 @@ interface UserRepositoryInterface
public function getUserGroups(User $user): Collection; public function getUserGroups(User $user): Collection;
public function hasRole(null|Authenticatable|User $user, string $role): bool; public function hasRole(null | Authenticatable | User $user, string $role): bool;
public function inviteUser(null|Authenticatable|User $user, string $email): InvitedUser; public function inviteUser(null | Authenticatable | User $user, string $email): InvitedUser;
public function redeemCode(string $code): void; public function redeemCode(string $code): void;

View File

@@ -35,6 +35,8 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Override;
use ValueError;
/** /**
* Class UserGroupRepository * Class UserGroupRepository
@@ -51,7 +53,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
/** @var GroupMembership $membership */ /** @var GroupMembership $membership */
foreach ($memberships as $membership) { foreach ($memberships as $membership) {
/** @var null|User $user */ /** @var null|User $user */
$user = $membership->user()->first(); $user = $membership->user()->first();
if (null === $user) { if (null === $user) {
continue; continue;
} }
@@ -80,8 +82,8 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
// all users are now moved away from user group. // all users are now moved away from user group.
// time to DESTROY all objects. // time to DESTROY all objects.
// we have to do this one by one to trigger the necessary observers :( // we have to do this one by one to trigger the necessary observers :(
$objects = ['availableBudgets', 'bills', 'budgets', 'categories', 'currencyExchangeRates', 'objectGroups', $objects = ['availableBudgets', 'bills', 'budgets', 'categories', 'currencyExchangeRates', 'objectGroups',
'recurrences', 'rules', 'ruleGroups', 'tags', 'transactionGroups', 'transactionJournals', 'piggyBanks', 'accounts', 'webhooks', 'recurrences', 'rules', 'ruleGroups', 'tags', 'transactionGroups', 'transactionJournals', 'piggyBanks', 'accounts', 'webhooks',
]; ];
foreach ($objects as $object) { foreach ($objects as $object) {
foreach ($userGroup->{$object}()->get() as $item) { // @phpstan-ignore-line foreach ($userGroup->{$object}()->get() as $item) { // @phpstan-ignore-line
@@ -108,7 +110,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
/** @var null|UserGroup $group */ /** @var null|UserGroup $group */
$group = $membership->userGroup()->first(); $group = $membership->userGroup()->first();
if (null !== $group) { if (null !== $group) {
$groupId = $group->id; $groupId = $group->id;
if (in_array($groupId, array_keys($set), true)) { if (in_array($groupId, array_keys($set), true)) {
continue; continue;
} }
@@ -133,14 +135,14 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
while ($exists && $loop < 10) { while ($exists && $loop < 10) {
$existingGroup = $this->findByName($groupName); $existingGroup = $this->findByName($groupName);
if (null === $existingGroup) { if (null === $existingGroup) {
$exists = false; $exists = false;
/** @var null|UserGroup $existingGroup */ /** @var null|UserGroup $existingGroup */
$existingGroup = $this->store(['user' => $user, 'title' => $groupName]); $existingGroup = $this->store(['user' => $user, 'title' => $groupName]);
} }
if (null !== $existingGroup) { if (null !== $existingGroup) {
// group already exists // group already exists
$groupName = sprintf('%s-%s', $user->email, substr(sha1(rand(1000, 9999).microtime()), 0, 4)); $groupName = sprintf('%s-%s', $user->email, substr(sha1(rand(1000, 9999) . microtime()), 0, 4));
} }
++$loop; ++$loop;
} }
@@ -161,7 +163,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
$data['user'] = $this->user; $data['user'] = $this->user;
/** @var UserGroupFactory $factory */ /** @var UserGroupFactory $factory */
$factory = app(UserGroupFactory::class); $factory = app(UserGroupFactory::class);
return $factory->create($data); return $factory->create($data);
} }
@@ -176,13 +178,13 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
return UserGroup::all(); return UserGroup::all();
} }
#[\Override] #[Override]
public function getById(int $id): ?UserGroup public function getById(int $id): ?UserGroup
{ {
return UserGroup::find($id); return UserGroup::find($id);
} }
#[\Override] #[Override]
public function getMembershipsFromGroupId(int $groupId): Collection public function getMembershipsFromGroupId(int $groupId): Collection
{ {
return $this->user->groupMemberships()->where('user_group_id', $groupId)->get(); return $this->user->groupMemberships()->where('user_group_id', $groupId)->get();
@@ -192,10 +194,10 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
{ {
$userGroup->title = $data['title']; $userGroup->title = $data['title'];
$userGroup->save(); $userGroup->save();
$currency = null; $currency = null;
/** @var CurrencyRepositoryInterface $repository */ /** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class); $repository = app(CurrencyRepositoryInterface::class);
if (array_key_exists('native_currency_code', $data)) { if (array_key_exists('native_currency_code', $data)) {
$repository->setUser($this->user); $repository->setUser($this->user);
@@ -221,11 +223,11 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
*/ */
public function updateMembership(UserGroup $userGroup, array $data): UserGroup public function updateMembership(UserGroup $userGroup, array $data): UserGroup
{ {
$owner = UserRole::whereTitle(UserRoleEnum::OWNER)->first(); $owner = UserRole::whereTitle(UserRoleEnum::OWNER)->first();
app('log')->debug('in update membership'); app('log')->debug('in update membership');
/** @var null|User $user */ /** @var null|User $user */
$user = null; $user = null;
if (array_key_exists('id', $data)) { if (array_key_exists('id', $data)) {
/** @var null|User $user */ /** @var null|User $user */
$user = User::find($data['id']); $user = User::find($data['id']);
@@ -264,9 +266,8 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
if ($membershipCount > 1) { if ($membershipCount > 1) {
// group has multiple members. How many are owner, except the user we're editing now? // group has multiple members. How many are owner, except the user we're editing now?
$ownerCount = $userGroup->groupMemberships() $ownerCount = $userGroup->groupMemberships()
->where('user_role_id', $owner->id) ->where('user_role_id', $owner->id)
->where('user_id', '!=', $user->id)->count() ->where('user_id', '!=', $user->id)->count();
;
// if there are no other owners and the current users does not get or keep the owner role, refuse. // if there are no other owners and the current users does not get or keep the owner role, refuse.
if ( if (
0 === $ownerCount 0 === $ownerCount
@@ -286,7 +287,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
foreach ($rolesSimplified as $role) { foreach ($rolesSimplified as $role) {
try { try {
$enum = UserRoleEnum::from($role); $enum = UserRoleEnum::from($role);
} catch (\ValueError $e) { } catch (ValueError $e) {
// TODO error message // TODO error message
continue; continue;
} }
@@ -313,7 +314,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
return $roles; return $roles;
} }
#[\Override] #[Override]
public function useUserGroup(UserGroup $userGroup): void public function useUserGroup(UserGroup $userGroup): void
{ {
$this->user->user_group_id = $userGroup->id; $this->user->user_group_id = $userGroup->id;

View File

@@ -37,6 +37,8 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Override;
use stdClass;
/** /**
* Class AccountRepository * Class AccountRepository
@@ -47,7 +49,7 @@ class AccountRepository implements AccountRepositoryInterface
{ {
use UserGroupTrait; use UserGroupTrait;
#[\Override] #[Override]
public function countAccounts(array $types): int public function countAccounts(array $types): int
{ {
$query = $this->userGroup->accounts(); $query = $this->userGroup->accounts();
@@ -70,8 +72,7 @@ class AccountRepository implements AccountRepositoryInterface
$q1->where('account_meta.name', '=', 'account_number'); $q1->where('account_meta.name', '=', 'account_number');
$q1->where('account_meta.data', '=', $json); $q1->where('account_meta.data', '=', $json);
} }
) );
;
if (0 !== count($types)) { if (0 !== count($types)) {
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); $dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
@@ -98,7 +99,7 @@ class AccountRepository implements AccountRepositoryInterface
public function findByName(string $name, array $types): ?Account public function findByName(string $name, array $types): ?Account
{ {
$query = $this->userGroup->accounts(); $query = $this->userGroup->accounts();
if (0 !== count($types)) { if (0 !== count($types)) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id'); $query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
@@ -120,7 +121,7 @@ class AccountRepository implements AccountRepositoryInterface
return $account; return $account;
} }
#[\Override] #[Override]
public function getAccountBalances(Account $account): Collection public function getAccountBalances(Account $account): Collection
{ {
return $account->accountBalances; return $account->accountBalances;
@@ -128,8 +129,8 @@ class AccountRepository implements AccountRepositoryInterface
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)) {
@@ -174,13 +175,12 @@ class AccountRepository implements AccountRepositoryInterface
return $account; return $account;
} }
#[\Override] #[Override]
public function getAccountTypes(Collection $accounts): Collection public function getAccountTypes(Collection $accounts): Collection
{ {
return AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id') return AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accounts->pluck('id')->toArray()) ->whereIn('accounts.id', $accounts->pluck('id')->toArray())
->get(['accounts.id', 'account_types.type']) ->get(['accounts.id', 'account_types.type']);
;
} }
public function getAccountsById(array $accountIds): Collection public function getAccountsById(array $accountIds): Collection
@@ -197,7 +197,7 @@ class AccountRepository implements AccountRepositoryInterface
return $query->get(['accounts.*']); return $query->get(['accounts.*']);
} }
#[\Override] #[Override]
public function getAccountsInOrder(array $types, array $sort, int $startRow, int $endRow): Collection public function getAccountsInOrder(array $types, array $sort, int $startRow, int $endRow): Collection
{ {
$query = $this->userGroup->accounts(); $query = $this->userGroup->accounts();
@@ -237,17 +237,17 @@ class AccountRepository implements AccountRepositoryInterface
return $query->get(['accounts.*']); return $query->get(['accounts.*']);
} }
#[\Override] #[Override]
public function getLastActivity(Collection $accounts): array public function getLastActivity(Collection $accounts): array
{ {
return Transaction::whereIn('account_id', $accounts->pluck('id')->toArray()) return Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
->groupBy('transactions.account_id') ->groupBy('transactions.account_id')
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray() // @phpstan-ignore-line ->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray() // @phpstan-ignore-line
; ;
} }
#[\Override] #[Override]
public function getMetaValues(Collection $accounts, array $fields): Collection public function getMetaValues(Collection $accounts, array $fields): Collection
{ {
$query = AccountMeta::whereIn('account_id', $accounts->pluck('id')->toArray()); $query = AccountMeta::whereIn('account_id', $accounts->pluck('id')->toArray());
@@ -258,23 +258,22 @@ class AccountRepository implements AccountRepositoryInterface
return $query->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data']); return $query->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data']);
} }
#[\Override] #[Override]
public function getObjectGroups(Collection $accounts): array public function getObjectGroups(Collection $accounts): array
{ {
$groupIds = []; $groupIds = [];
$return = []; $return = [];
$set = DB::table('object_groupables')->where('object_groupable_type', Account::class) $set = DB::table('object_groupables')->where('object_groupable_type', Account::class)
->whereIn('object_groupable_id', $accounts->pluck('id')->toArray())->get() ->whereIn('object_groupable_id', $accounts->pluck('id')->toArray())->get();
;
/** @var \stdClass $row */ /** @var stdClass $row */
foreach ($set as $row) { foreach ($set as $row) {
$groupIds[] = $row->object_group_id; $groupIds[] = $row->object_group_id;
} }
$groupIds = array_unique($groupIds); $groupIds = array_unique($groupIds);
$groups = ObjectGroup::whereIn('id', $groupIds)->get(); $groups = ObjectGroup::whereIn('id', $groupIds)->get();
/** @var \stdClass $row */ /** @var stdClass $row */
foreach ($set as $row) { foreach ($set as $row) {
if (!array_key_exists($row->object_groupable_id, $return)) { if (!array_key_exists($row->object_groupable_id, $return)) {
/** @var null|ObjectGroup $group */ /** @var null|ObjectGroup $group */
@@ -312,18 +311,17 @@ class AccountRepository implements AccountRepositoryInterface
} }
} }
// reset the rest to zero. // reset the rest to zero.
$all = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value]; $all = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value];
$this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') $this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereNotIn('account_types.type', $all) ->whereNotIn('account_types.type', $all)
->update(['order' => 0]) ->update(['order' => 0]);
;
} }
public function getAccountsByType(array $types, ?array $sort = [], ?array $filters = []): Collection public function getAccountsByType(array $types, ?array $sort = [], ?array $filters = []): Collection
{ {
$sortable = ['name', 'active']; // TODO yes this is a duplicate array. $sortable = ['name', 'active']; // TODO yes this is a duplicate array.
$res = array_intersect([AccountTypeEnum::ASSET->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value], $types); $res = array_intersect([AccountTypeEnum::ASSET->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value], $types);
$query = $this->userGroup->accounts(); $query = $this->userGroup->accounts();
if (0 !== count($types)) { if (0 !== count($types)) {
$query->accountTypeIn($types); $query->accountTypeIn($types);
} }
@@ -370,7 +368,7 @@ class AccountRepository implements AccountRepositoryInterface
return $query->get(['accounts.*']); return $query->get(['accounts.*']);
} }
#[\Override] #[Override]
public function update(Account $account, array $data): Account public function update(Account $account, array $data): Account
{ {
/** @var AccountUpdateService $service */ /** @var AccountUpdateService $service */
@@ -383,13 +381,12 @@ class AccountRepository implements AccountRepositoryInterface
{ {
// search by group, not by user // search by group, not by user
$dbQuery = $this->userGroup->accounts() $dbQuery = $this->userGroup->accounts()
->where('active', true) ->where('active', true)
->orderBy('accounts.updated_at', 'ASC') ->orderBy('accounts.updated_at', 'ASC')
->orderBy('accounts.order', 'ASC') ->orderBy('accounts.order', 'ASC')
->orderBy('accounts.account_type_id', 'ASC') ->orderBy('accounts.account_type_id', 'ASC')
->orderBy('accounts.name', 'ASC') ->orderBy('accounts.name', 'ASC')
->with(['accountType']) ->with(['accountType']);
;
// split query on spaces just in case: // split query on spaces just in case:
if ('' !== trim($query)) { if ('' !== trim($query)) {

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Repositories\UserGroups\Account;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**

View File

@@ -62,9 +62,8 @@ class BillRepository implements BillRepositoryInterface
public function getBills(): Collection public function getBills(): Collection
{ {
return $this->userGroup->bills() return $this->userGroup->bills()
->orderBy('bills.name', 'ASC') ->orderBy('bills.name', 'ASC')
->get(['bills.*']) ->get(['bills.*']);
;
} }
public function sumPaidInRange(Carbon $start, Carbon $end): array public function sumPaidInRange(Carbon $start, Carbon $end): array
@@ -102,13 +101,13 @@ class BillRepository implements BillRepositoryInterface
/** @var null|Transaction $sourceTransaction */ /** @var null|Transaction $sourceTransaction */
$sourceTransaction = $transactionJournal->transactions()->where('amount', '<', 0)->first(); $sourceTransaction = $transactionJournal->transactions()->where('amount', '<', 0)->first();
if (null !== $sourceTransaction) { if (null !== $sourceTransaction) {
$amount = $sourceTransaction->amount; $amount = $sourceTransaction->amount;
if ((int) $sourceTransaction->foreign_currency_id === $currency->id) { if ((int) $sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead! // use foreign amount instead!
$amount = (string) $sourceTransaction->foreign_amount; $amount = (string) $sourceTransaction->foreign_amount;
} }
// convert to native currency // convert to native currency
$nativeAmount = $amount; $nativeAmount = $amount;
if ($currencyId !== $default->id) { if ($currencyId !== $default->id) {
// get rate and convert. // get rate and convert.
$nativeAmount = $converter->convert($currency, $default, $transactionJournal->date, $amount); $nativeAmount = $converter->convert($currency, $default, $transactionJournal->date, $amount);
@@ -130,10 +129,9 @@ class BillRepository implements BillRepositoryInterface
public function getActiveBills(): Collection public function getActiveBills(): Collection
{ {
return $this->userGroup->bills() return $this->userGroup->bills()
->where('active', true) ->where('active', true)
->orderBy('bills.name', 'ASC') ->orderBy('bills.name', 'ASC')
->get(['bills.*']) ->get(['bills.*']);
;
} }
public function sumUnpaidInRange(Carbon $start, Carbon $end): array public function sumUnpaidInRange(Carbon $start, Carbon $end): array
@@ -155,7 +153,7 @@ class BillRepository implements BillRepositoryInterface
$currencyId = $bill->transaction_currency_id; $currencyId = $bill->transaction_currency_id;
$average = bcdiv(bcadd($bill->amount_max, $bill->amount_min), '2'); $average = bcdiv(bcadd($bill->amount_max, $bill->amount_min), '2');
$nativeAverage = $converter->convert($currency, $default, $start, $average); $nativeAverage = $converter->convert($currency, $default, $start, $average);
$return[$currencyId] ??= [ $return[$currencyId] ??= [
'currency_id' => (string) $currency->id, 'currency_id' => (string) $currency->id,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
@@ -202,7 +200,7 @@ class BillRepository implements BillRepositoryInterface
// app('log')->debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d'))); // app('log')->debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
$currentStart = clone $nextExpectedMatch; $currentStart = clone $nextExpectedMatch;
} }
return $set; return $set;

View File

@@ -46,14 +46,13 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
$default = app('amount')->getNativeCurrency(); $default = app('amount')->getNativeCurrency();
$availableBudgets = $this->userGroup->availableBudgets() $availableBudgets = $this->userGroup->availableBudgets()
->where('start_date', $start->format('Y-m-d')) ->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->get() ->where('end_date', $end->format('Y-m-d'))->get();
;
/** @var AvailableBudget $availableBudget */ /** @var AvailableBudget $availableBudget */
foreach ($availableBudgets as $availableBudget) { foreach ($availableBudgets as $availableBudget) {
$currencyId = $availableBudget->transaction_currency_id; $currencyId = $availableBudget->transaction_currency_id;
$return[$currencyId] ??= [ $return[$currencyId] ??= [
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_code' => $availableBudget->transactionCurrency->code, 'currency_code' => $availableBudget->transactionCurrency->code,
'currency_symbol' => $availableBudget->transactionCurrency->symbol, 'currency_symbol' => $availableBudget->transactionCurrency->symbol,

View File

@@ -39,18 +39,16 @@ class BudgetRepository implements BudgetRepositoryInterface
public function getActiveBudgets(): Collection public function getActiveBudgets(): Collection
{ {
return $this->userGroup->budgets()->where('active', true) return $this->userGroup->budgets()->where('active', true)
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('name', 'ASC') ->orderBy('name', 'ASC')
->get() ->get();
;
} }
public function getBudgets(): Collection public function getBudgets(): Collection
{ {
return $this->userGroup->budgets() return $this->userGroup->budgets()
->orderBy('order', 'ASC') ->orderBy('order', 'ASC')
->orderBy('name', 'ASC') ->orderBy('name', 'ASC')
->get() ->get();
;
} }
} }

View File

@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -58,13 +59,13 @@ class OperationsRepository implements OperationsRepositoryInterface
$collector->setBudgets($this->getBudgets()); $collector->setBudgets($this->getBudgets());
} }
$collector->withBudgetInformation()->withAccountInformation()->withCategoryInformation(); $collector->withBudgetInformation()->withAccountInformation()->withCategoryInformation();
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$budgetId = (int) $journal['budget_id']; $budgetId = (int) $journal['budget_id'];
$budgetName = (string) $journal['budget_name']; $budgetName = (string) $journal['budget_name'];
// catch "no budget" entries. // catch "no budget" entries.
if (0 === $budgetId) { if (0 === $budgetId) {
@@ -72,7 +73,7 @@ class OperationsRepository implements OperationsRepositoryInterface
} }
// info about the currency: // info about the currency:
$array[$currencyId] ??= [ $array[$currencyId] ??= [
'budgets' => [], 'budgets' => [],
'currency_id' => $currencyId, 'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
@@ -90,8 +91,8 @@ class OperationsRepository implements OperationsRepositoryInterface
// add journal to array: // add journal to array:
// only a subset of the fields. // only a subset of the fields.
$journalId = (int) $journal['transaction_journal_id']; $journalId = (int) $journal['transaction_journal_id'];
$final = [ $final = [
'amount' => app('steam')->negative($journal['amount']), 'amount' => app('steam')->negative($journal['amount']),
'currency_id' => $journal['currency_id'], 'currency_id' => $journal['currency_id'],
'foreign_amount' => null, 'foreign_amount' => null,

View File

@@ -66,7 +66,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
public function currencyInUseAt(TransactionCurrency $currency): ?string public function currencyInUseAt(TransactionCurrency $currency): ?string
{ {
app('log')->debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code)); app('log')->debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
$countJournals = $this->countJournals($currency); $countJournals = $this->countJournals($currency);
if ($countJournals > 0) { if ($countJournals > 0) {
app('log')->info(sprintf('Count journals is %d, return true.', $countJournals)); app('log')->info(sprintf('Count journals is %d, return true.', $countJournals));
@@ -81,7 +81,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// is being used in accounts: // is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count(); $meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
if ($meta > 0) { if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta)); app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -89,7 +89,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// second search using integer check. // second search using integer check.
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count(); $meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
if ($meta > 0) { if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta)); app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -97,7 +97,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// is being used in bills: // is being used in bills:
$bills = Bill::where('transaction_currency_id', $currency->id)->count(); $bills = Bill::where('transaction_currency_id', $currency->id)->count();
if ($bills > 0) { if ($bills > 0) {
app('log')->info(sprintf('Used in %d bills as currency, return true. ', $bills)); app('log')->info(sprintf('Used in %d bills as currency, return true. ', $bills));
@@ -115,10 +115,9 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// is being used in accounts (as integer) // is being used in accounts (as integer)
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id') $meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
->whereNull('accounts.deleted_at') ->whereNull('accounts.deleted_at')
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count() ->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count();
;
if ($meta > 0) { if ($meta > 0) {
app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta)); app('log')->info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -134,7 +133,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// is being used in budget limits // is being used in budget limits
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count(); $budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
if ($budgetLimit > 0) { if ($budgetLimit > 0) {
app('log')->info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit)); app('log')->info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit));
@@ -142,7 +141,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// is the default currency for the user or the system // is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count(); $count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) { if ($count > 0) {
app('log')->info('Is the default currency of the user, return true.'); app('log')->info('Is the default currency of the user, return true.');
@@ -150,7 +149,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
// is the default currency for the user or the system // is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count(); $count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) { if ($count > 0) {
app('log')->info('Is the default currency of the user group, return true.'); app('log')->info('Is the default currency of the user group, return true.');

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Repositories\UserGroups\Currency;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Override;
/** /**
* Class ExchangeRateRepository * Class ExchangeRateRepository
@@ -40,55 +41,51 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface
{ {
use UserGroupTrait; use UserGroupTrait;
#[\Override] #[Override]
public function deleteRate(CurrencyExchangeRate $rate): void public function deleteRate(CurrencyExchangeRate $rate): void
{ {
$this->userGroup->currencyExchangeRates()->where('id', $rate->id)->delete(); $this->userGroup->currencyExchangeRates()->where('id', $rate->id)->delete();
} }
#[\Override] #[Override]
public function getAll(): Collection public function getAll(): Collection
{ {
return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get(); return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get();
} }
#[\Override] #[Override]
public function getRates(TransactionCurrency $from, TransactionCurrency $to): Collection public function getRates(TransactionCurrency $from, TransactionCurrency $to): Collection
{ {
// orderBy('date', 'DESC')->toRawSql(); // orderBy('date', 'DESC')->toRawSql();
return return
$this->userGroup->currencyExchangeRates() $this->userGroup->currencyExchangeRates()
->where(function (Builder $q1) use ($from, $to): void { ->where(function (Builder $q1) use ($from, $to): void {
$q1->where(function (Builder $q) use ($from, $to): void { $q1->where(function (Builder $q) use ($from, $to): void {
$q->where('from_currency_id', $from->id) $q->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id) ->where('to_currency_id', $to->id);
; })->orWhere(function (Builder $q) use ($from, $to): void {
})->orWhere(function (Builder $q) use ($from, $to): void { $q->where('from_currency_id', $to->id)
$q->where('from_currency_id', $to->id) ->where('to_currency_id', $from->id);
->where('to_currency_id', $from->id) });
; })
}); ->orderBy('date', 'DESC')
}) ->get(['currency_exchange_rates.*']);
->orderBy('date', 'DESC')
->get(['currency_exchange_rates.*'])
;
} }
#[\Override] #[Override]
public function getSpecificRateOnDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): ?CurrencyExchangeRate public function getSpecificRateOnDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): ?CurrencyExchangeRate
{ {
/** @var null|CurrencyExchangeRate */ /** @var null|CurrencyExchangeRate */
return return
$this->userGroup->currencyExchangeRates() $this->userGroup->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', $date->format('Y-m-d')) ->where('date', $date->format('Y-m-d'))
->first() ->first();
;
} }
#[\Override] #[Override]
public function storeExchangeRate(TransactionCurrency $from, TransactionCurrency $to, string $rate, Carbon $date): CurrencyExchangeRate public function storeExchangeRate(TransactionCurrency $from, TransactionCurrency $to, string $rate, Carbon $date): CurrencyExchangeRate
{ {
$object = new CurrencyExchangeRate(); $object = new CurrencyExchangeRate();
@@ -104,7 +101,7 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface
return $object; return $object;
} }
#[\Override] #[Override]
public function updateExchangeRate(CurrencyExchangeRate $object, string $rate, ?Carbon $date = null): CurrencyExchangeRate public function updateExchangeRate(CurrencyExchangeRate $object, string $rate, ?Carbon $date = null): CurrencyExchangeRate
{ {
$object->rate = $rate; $object->rate = $rate;

View File

@@ -40,8 +40,7 @@ class JournalRepository implements JournalRepositoryInterface
public function searchJournalDescriptions(array $query, int $limit): Collection public function searchJournalDescriptions(array $query, int $limit): Collection
{ {
$search = $this->userGroup->transactionJournals() $search = $this->userGroup->transactionJournals()
->orderBy('date', 'DESC') ->orderBy('date', 'DESC');
;
if (count($query) > 0) { if (count($query) > 0) {
// split query on spaces just in case: // split query on spaces just in case:
$search->where(function (EloquentBuilder $q) use ($query): void { $search->where(function (EloquentBuilder $q) use ($query): void {

View File

@@ -40,14 +40,13 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
public function getPiggyBanks(): Collection public function getPiggyBanks(): Collection
{ {
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_group_id', $this->userGroup->id) ->where('accounts.user_group_id', $this->userGroup->id)
->with( ->with(
[ [
'objectGroups', 'objectGroups',
] ]
) )
->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']) ->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']);
;
} }
} }

View File

@@ -67,23 +67,21 @@ class WebhookRepository implements WebhookRepositoryInterface, UserGroupInterfac
public function getMessages(Webhook $webhook): Collection public function getMessages(Webhook $webhook): Collection
{ {
return $webhook->webhookMessages() return $webhook->webhookMessages()
->orderBy('created_at', 'DESC') ->orderBy('created_at', 'DESC')
->get(['webhook_messages.*']) ->get(['webhook_messages.*']);
;
} }
public function getReadyMessages(Webhook $webhook): Collection public function getReadyMessages(Webhook $webhook): Collection
{ {
return $webhook->webhookMessages() return $webhook->webhookMessages()
->where('webhook_messages.sent', 0) ->where('webhook_messages.sent', 0)
->where('webhook_messages.errored', 0) ->where('webhook_messages.errored', 0)
->get(['webhook_messages.*']) ->get(['webhook_messages.*'])
->filter( ->filter(
static function (WebhookMessage $message) { // @phpstan-ignore-line static function (WebhookMessage $message) { // @phpstan-ignore-line
return $message->webhookAttempts()->count() <= 2; return $message->webhookAttempts()->count() <= 2;
} }
)->splice(0, 3) )->splice(0, 3);
;
} }
public function store(array $data): Webhook public function store(array $data): Webhook

View File

@@ -49,19 +49,9 @@ use Illuminate\Support\Facades\Log;
*/ */
class AccountEnrichment implements EnrichmentInterface class AccountEnrichment implements EnrichmentInterface
{ {
// private array $balances;
// private array $currencies;
// private CurrencyRepositoryInterface $currencyRepository;
// private TransactionCurrency $default;
// private ?Carbon $end;
// private array $grouped;
// private array $objectGroups;
// private AccountRepositoryInterface $repository;
// private ?Carbon $start;
private Collection $collection; private Collection $collection;
private bool $convertToNative;
private User $user; private User $user;
private UserGroup $userGroup; private UserGroup $userGroup;
private TransactionCurrency $native; private TransactionCurrency $native;
@@ -76,7 +66,6 @@ class AccountEnrichment implements EnrichmentInterface
public function __construct() public function __construct()
{ {
$this->convertToNative = false;
$this->accountIds = []; $this->accountIds = [];
$this->openingBalances = []; $this->openingBalances = [];
$this->currencies = []; $this->currencies = [];
@@ -197,7 +186,10 @@ class AccountEnrichment implements EnrichmentInterface
// use new group collector: // use new group collector:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setAccounts($this->collection) $collector
->setUser($this->user)
->setUserGroup($this->userGroup)
->setAccounts($this->collection)
->withAccountInformation() ->withAccountInformation()
->setTypes([TransactionTypeEnum::OPENING_BALANCE->value]) ->setTypes([TransactionTypeEnum::OPENING_BALANCE->value])
; ;
@@ -269,11 +261,6 @@ class AccountEnrichment implements EnrichmentInterface
$this->userGroup = $user->userGroup; $this->userGroup = $user->userGroup;
} }
public function setConvertToNative(bool $convertToNative): void
{
$this->convertToNative = $convertToNative;
}
public function setNative(TransactionCurrency $native): void public function setNative(TransactionCurrency $native): void
{ {
$this->native = $native; $this->native = $native;

View File

@@ -47,8 +47,8 @@ class TransactionGroupEnrichment implements EnrichmentInterface
private array $tags; private array $tags;
private array $locations; private array $locations;
private array $journalIds; private array $journalIds;
private User $user; private User $user; // @phpstan-ignore-line
private UserGroup $userGroup; private UserGroup $userGroup; // @phpstan-ignore-line
private array $metaData; private array $metaData;
private array $dateFields; private array $dateFields;
private array $attachmentCount; private array $attachmentCount;

View File

@@ -24,10 +24,6 @@ declare(strict_types=1);
use FireflyIII\User; use FireflyIII\User;
if ('ldap' === strtolower((string) env('AUTHENTICATION_GUARD'))) {
exit('LDAP is no longer supported by Firefly III v5.7+. Sorry about that. You will have to switch to "remote_user_guard", and use tools like Authelia or Keycloak to use LDAP together with Firefly III.');
}
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------