mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-23 04:46:44 +00:00
Auto commit for release 'develop' on 2025-03-14
This commit is contained in:
24
.ci/php-cs-fixer/composer.lock
generated
24
.ci/php-cs-fixer/composer.lock
generated
@@ -406,16 +406,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "friendsofphp/php-cs-fixer",
|
"name": "friendsofphp/php-cs-fixer",
|
||||||
"version": "v3.70.2",
|
"version": "v3.72.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||||
"reference": "1ca468270efbb75ce0c7566a79cca8ea2888584d"
|
"reference": "900389362c43d116fee1ffc51f7878145fa61b57"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1ca468270efbb75ce0c7566a79cca8ea2888584d",
|
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/900389362c43d116fee1ffc51f7878145fa61b57",
|
||||||
"reference": "1ca468270efbb75ce0c7566a79cca8ea2888584d",
|
"reference": "900389362c43d116fee1ffc51f7878145fa61b57",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -445,18 +445,18 @@
|
|||||||
"symfony/stopwatch": "^5.4 || ^6.4 || ^7.0"
|
"symfony/stopwatch": "^5.4 || ^6.4 || ^7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"facile-it/paraunit": "^1.3.1 || ^2.5",
|
"facile-it/paraunit": "^1.3.1 || ^2.6",
|
||||||
"infection/infection": "^0.29.10",
|
"infection/infection": "^0.29.14",
|
||||||
"justinrainbow/json-schema": "^5.3 || ^6.0",
|
"justinrainbow/json-schema": "^5.3 || ^6.2",
|
||||||
"keradus/cli-executor": "^2.1",
|
"keradus/cli-executor": "^2.1",
|
||||||
"mikey179/vfsstream": "^1.6.12",
|
"mikey179/vfsstream": "^1.6.12",
|
||||||
"php-coveralls/php-coveralls": "^2.7",
|
"php-coveralls/php-coveralls": "^2.7",
|
||||||
"php-cs-fixer/accessible-object": "^1.1",
|
"php-cs-fixer/accessible-object": "^1.1",
|
||||||
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
|
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
|
||||||
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
|
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
|
||||||
"phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.7",
|
"phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12",
|
||||||
"symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.0",
|
"symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3",
|
||||||
"symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.0"
|
"symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-dom": "For handling output formats in XML",
|
"ext-dom": "For handling output formats in XML",
|
||||||
@@ -497,7 +497,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.70.2"
|
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.72.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -505,7 +505,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-03-03T21:07:23+00:00"
|
"time": "2025-03-13T11:25:37+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
|
@@ -82,7 +82,7 @@ class UpdateRequest extends FormRequest
|
|||||||
'accounts' => 'required',
|
'accounts' => 'required',
|
||||||
'accounts.*' => 'array|required',
|
'accounts.*' => 'array|required',
|
||||||
'accounts.*.account_id' => ['required', 'numeric', 'belongsToUser:accounts,id'],
|
'accounts.*.account_id' => ['required', 'numeric', 'belongsToUser:accounts,id'],
|
||||||
'accounts.*.current_amount' => ['numeric','nullable', new IsValidZeroOrMoreAmount(true)],
|
'accounts.*.current_amount' => ['numeric', 'nullable', new IsValidZeroOrMoreAmount(true)],
|
||||||
'object_group_id' => 'numeric|belongsToUser:object_groups,id',
|
'object_group_id' => 'numeric|belongsToUser:object_groups,id',
|
||||||
'object_group_title' => ['min:1', 'max:255'],
|
'object_group_title' => ['min:1', 'max:255'],
|
||||||
'transaction_currency_id' => 'exists:transaction_currencies,id|nullable',
|
'transaction_currency_id' => 'exists:transaction_currencies,id|nullable',
|
||||||
|
@@ -122,7 +122,8 @@ class CorrectsUnevenAmount extends Command
|
|||||||
$journals = DB::table('transactions')
|
$journals = DB::table('transactions')
|
||||||
->groupBy('transaction_journal_id')
|
->groupBy('transaction_journal_id')
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]);
|
->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')])
|
||||||
|
;
|
||||||
|
|
||||||
/** @var \stdClass $entry */
|
/** @var \stdClass $entry */
|
||||||
foreach ($journals as $entry) {
|
foreach ($journals as $entry) {
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
/*
|
/*
|
||||||
* ValidatesEnvironmentVariables.php
|
* ValidatesEnvironmentVariables.php
|
||||||
* Copyright (c) 2025 james@firefly-iii.org.
|
* Copyright (c) 2025 james@firefly-iii.org.
|
||||||
@@ -33,12 +35,12 @@ class ValidatesEnvironmentVariables extends Command
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'integrity:validates-environment-variables';
|
protected $signature = 'integrity:validates-environment-variables';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
*
|
*
|
||||||
* @var string|null
|
* @var null|string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Makes sure you use the correct variables.';
|
protected $description = 'Makes sure you use the correct variables.';
|
||||||
|
|
||||||
@@ -50,19 +52,21 @@ class ValidatesEnvironmentVariables extends Command
|
|||||||
$this->validateLanguage();
|
$this->validateLanguage();
|
||||||
$this->validateGuard();
|
$this->validateGuard();
|
||||||
$this->validateStaticToken();
|
$this->validateStaticToken();
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function validateLanguage(): void
|
private function validateLanguage(): void
|
||||||
{
|
{
|
||||||
$language = config('firefly.default_language');
|
$language = config('firefly.default_language');
|
||||||
$locale = config('firefly.default_locale');
|
$locale = config('firefly.default_locale');
|
||||||
$options = array_keys(config('firefly.languages'));
|
$options = array_keys(config('firefly.languages'));
|
||||||
|
|
||||||
if (!in_array($language, $options, true)) {
|
if (!in_array($language, $options, true)) {
|
||||||
$this->friendlyError(sprintf('DEFAULT_LANGUAGE "%s" is not a valid language for Firefly III.', $language));
|
$this->friendlyError(sprintf('DEFAULT_LANGUAGE "%s" is not a valid language for Firefly III.', $language));
|
||||||
$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.');
|
||||||
$this->friendlyError(sprintf('Valid languages are: %s', implode(', ', $options)));
|
$this->friendlyError(sprintf('Valid languages are: %s', implode(', ', $options)));
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
$options[] = 'equal';
|
$options[] = 'equal';
|
||||||
@@ -70,6 +74,7 @@ class ValidatesEnvironmentVariables extends Command
|
|||||||
$this->friendlyError(sprintf('DEFAULT_LOCALE "%s" is not a valid local for Firefly III.', $locale));
|
$this->friendlyError(sprintf('DEFAULT_LOCALE "%s" is not a valid local for Firefly III.', $locale));
|
||||||
$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.');
|
||||||
$this->friendlyError(sprintf('Valid locales are: %s', implode(', ', $options)));
|
$this->friendlyError(sprintf('Valid locales are: %s', implode(', ', $options)));
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,6 +86,7 @@ class ValidatesEnvironmentVariables extends Command
|
|||||||
$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.');
|
||||||
$this->friendlyError('Valid guards are: web, remote_user_guard');
|
$this->friendlyError('Valid guards are: web, remote_user_guard');
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,9 +94,10 @@ class ValidatesEnvironmentVariables extends Command
|
|||||||
private function validateStaticToken(): void
|
private function validateStaticToken(): void
|
||||||
{
|
{
|
||||||
$token = (string) config('firefly.static_cron_token');
|
$token = (string) config('firefly.static_cron_token');
|
||||||
if (0 !== strlen($token) && 32 !== strlen($token)) {
|
if ('' !== $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.');
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,8 +55,8 @@ class BillFactory
|
|||||||
$skip = array_key_exists('skip', $data) ? $data['skip'] : 0;
|
$skip = array_key_exists('skip', $data) ? $data['skip'] : 0;
|
||||||
$active = array_key_exists('active', $data) ? $data['active'] : 0;
|
$active = array_key_exists('active', $data) ? $data['active'] : 0;
|
||||||
|
|
||||||
$data['extension_date'] = $data['extension_date'] ?? null;
|
$data['extension_date'] ??= null;
|
||||||
$data['end_date'] = $data['end_date'] ?? null;
|
$data['end_date'] ??= null;
|
||||||
|
|
||||||
/** @var Bill $bill */
|
/** @var Bill $bill */
|
||||||
$bill = Bill::create(
|
$bill = Bill::create(
|
||||||
|
@@ -67,7 +67,7 @@ class PiggyBankFactory
|
|||||||
public function store(array $data): PiggyBank
|
public function store(array $data): PiggyBank
|
||||||
{
|
{
|
||||||
|
|
||||||
$piggyBankData = $data;
|
$piggyBankData = $data;
|
||||||
|
|
||||||
// unset some fields
|
// unset some fields
|
||||||
unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']);
|
unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']);
|
||||||
@@ -91,11 +91,11 @@ class PiggyBankFactory
|
|||||||
|
|
||||||
throw new FireflyException('400005: Could not store new piggy bank.', 0, $e);
|
throw new FireflyException('400005: Could not store new piggy bank.', 0, $e);
|
||||||
}
|
}
|
||||||
$piggyBank = $this->setOrder($piggyBank, $data);
|
$piggyBank = $this->setOrder($piggyBank, $data);
|
||||||
$this->linkToAccountIds($piggyBank, $data['accounts']);
|
$this->linkToAccountIds($piggyBank, $data['accounts']);
|
||||||
$this->piggyBankRepository->updateNote($piggyBank, $data['notes']);
|
$this->piggyBankRepository->updateNote($piggyBank, $data['notes']);
|
||||||
|
|
||||||
$objectGroupTitle = $data['object_group_title'] ?? '';
|
$objectGroupTitle = $data['object_group_title'] ?? '';
|
||||||
if ('' !== $objectGroupTitle) {
|
if ('' !== $objectGroupTitle) {
|
||||||
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
|
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
|
||||||
if (null !== $objectGroup) {
|
if (null !== $objectGroup) {
|
||||||
@@ -103,7 +103,7 @@ class PiggyBankFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// try also with ID
|
// try also with ID
|
||||||
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
|
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
|
||||||
if (0 !== $objectGroupId) {
|
if (0 !== $objectGroupId) {
|
||||||
$objectGroup = $this->findObjectGroupById($objectGroupId);
|
$objectGroup = $this->findObjectGroupById($objectGroupId);
|
||||||
if (null !== $objectGroup) {
|
if (null !== $objectGroup) {
|
||||||
@@ -111,7 +111,7 @@ class PiggyBankFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log::debug('Touch piggy bank');
|
Log::debug('Touch piggy bank');
|
||||||
$piggyBank->encrypted = false;
|
$piggyBank->encrypted = false;
|
||||||
$piggyBank->save();
|
$piggyBank->save();
|
||||||
$piggyBank->touch();
|
$piggyBank->touch();
|
||||||
|
|
||||||
@@ -144,10 +144,11 @@ class PiggyBankFactory
|
|||||||
// first find by ID:
|
// first find by ID:
|
||||||
if ($piggyBankId > 0) {
|
if ($piggyBankId > 0) {
|
||||||
$piggyBank = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
|
$piggyBank = 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)
|
->where('piggy_banks.id', $piggyBankId)
|
||||||
->first(['piggy_banks.*']);
|
->first(['piggy_banks.*'])
|
||||||
|
;
|
||||||
if (null !== $piggyBank) {
|
if (null !== $piggyBank) {
|
||||||
return $piggyBank;
|
return $piggyBank;
|
||||||
}
|
}
|
||||||
@@ -168,16 +169,17 @@ class PiggyBankFactory
|
|||||||
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)
|
->where('piggy_banks.name', $name)
|
||||||
->first(['piggy_banks.*']);
|
->first(['piggy_banks.*'])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank
|
private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank
|
||||||
{
|
{
|
||||||
$this->resetOrder();
|
$this->resetOrder();
|
||||||
$order = $this->getMaxOrder() + 1;
|
$order = $this->getMaxOrder() + 1;
|
||||||
if (array_key_exists('order', $data)) {
|
if (array_key_exists('order', $data)) {
|
||||||
$order = $data['order'];
|
$order = $data['order'];
|
||||||
}
|
}
|
||||||
@@ -192,14 +194,15 @@ class PiggyBankFactory
|
|||||||
{
|
{
|
||||||
// TODO duplicate code
|
// TODO duplicate code
|
||||||
$set = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
|
$set = 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')->get(['piggy_banks.*']);
|
->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*'])
|
||||||
|
;
|
||||||
$current = 1;
|
$current = 1;
|
||||||
foreach ($set as $piggyBank) {
|
foreach ($set as $piggyBank) {
|
||||||
if ($piggyBank->order !== $current) {
|
if ($piggyBank->order !== $current) {
|
||||||
|
@@ -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,7 +115,7 @@ 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;
|
||||||
@@ -130,7 +130,7 @@ class NetWorth implements NetWorthInterface
|
|||||||
$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 = app(CurrencyRepositoryInterface::class);
|
||||||
$this->currencyRepos->setUserGroup($this->userGroup);
|
$this->currencyRepos->setUserGroup($this->userGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,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,
|
||||||
|
@@ -83,7 +83,7 @@ class ShowController extends Controller
|
|||||||
public function show(Request $request, Account $account, ?Carbon $start = null, ?Carbon $end = null)
|
public function show(Request $request, Account $account, ?Carbon $start = null, ?Carbon $end = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
|
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
|
||||||
|
|
||||||
if (!$this->isEditableAccount($account)) {
|
if (!$this->isEditableAccount($account)) {
|
||||||
return $this->redirectAccountToAccount($account);
|
return $this->redirectAccountToAccount($account);
|
||||||
@@ -130,18 +130,20 @@ class ShowController extends Controller
|
|||||||
}
|
}
|
||||||
Log::debug('Collect transactions');
|
Log::debug('Collect transactions');
|
||||||
Timer::start('collection');
|
Timer::start('collection');
|
||||||
|
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector
|
$collector
|
||||||
->setAccounts(new Collection([$account]))
|
->setAccounts(new Collection([$account]))
|
||||||
->setLimit($pageSize)
|
->setLimit($pageSize)
|
||||||
->setPage($page)
|
->setPage($page)
|
||||||
->withAPIInformation()
|
->withAPIInformation()
|
||||||
->setRange($start, $end);
|
->setRange($start, $end)
|
||||||
|
;
|
||||||
// this search will not include transaction groups where this asset account (or liability)
|
// this search will not include transaction groups where this asset account (or liability)
|
||||||
// is just part of ONE of the journals. To force this:
|
// is just part of ONE of the journals. To force this:
|
||||||
$collector->setExpandGroupSearch(true);
|
$collector->setExpandGroupSearch(true);
|
||||||
$groups = $collector->getPaginatedGroups();
|
$groups = $collector->getPaginatedGroups();
|
||||||
|
|
||||||
Log::debug('End collect transactions');
|
Log::debug('End collect transactions');
|
||||||
Timer::stop('collection');
|
Timer::stop('collection');
|
||||||
@@ -149,21 +151,21 @@ class ShowController extends Controller
|
|||||||
// enrich data in arrays.
|
// enrich data in arrays.
|
||||||
|
|
||||||
// enrich
|
// enrich
|
||||||
// $enrichment = new TransactionGroupEnrichment();
|
// $enrichment = new TransactionGroupEnrichment();
|
||||||
// $enrichment->setUser(auth()->user());
|
// $enrichment->setUser(auth()->user());
|
||||||
// $groups->setCollection($enrichment->enrich($groups->getCollection()));
|
// $groups->setCollection($enrichment->enrich($groups->getCollection()));
|
||||||
|
|
||||||
|
|
||||||
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
|
||||||
$showAll = false;
|
$showAll = false;
|
||||||
// correct
|
// correct
|
||||||
$now = today()->endOfDay();
|
$now = today()->endOfDay();
|
||||||
if ($now->gt($end) || $now->lt($start)) {
|
if ($now->gt($end) || $now->lt($start)) {
|
||||||
$now = $end;
|
$now = $end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
|
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
|
||||||
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency);
|
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency);
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'accounts.show',
|
'accounts.show',
|
||||||
@@ -207,7 +209,7 @@ class ShowController extends Controller
|
|||||||
$today = today(config('app.timezone'));
|
$today = today(config('app.timezone'));
|
||||||
$accountCurrency = $this->repository->getAccountCurrency($account);
|
$accountCurrency = $this->repository->getAccountCurrency($account);
|
||||||
$start = $this->repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth();
|
$start = $this->repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth();
|
||||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
$subTitleIcon = config('firefly.subIconsByIdentifier.'.$account->accountType->type);
|
||||||
$page = (int) $request->get('page');
|
$page = (int) $request->get('page');
|
||||||
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
||||||
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
|
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
|
||||||
@@ -217,20 +219,20 @@ class ShowController extends Controller
|
|||||||
$end->endOfDay();
|
$end->endOfDay();
|
||||||
|
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();
|
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();
|
||||||
|
|
||||||
// this search will not include transaction groups where this asset account (or liability)
|
// this search will not include transaction groups where this asset account (or liability)
|
||||||
// is just part of ONE of the journals. To force this:
|
// is just part of ONE of the journals. To force this:
|
||||||
$collector->setExpandGroupSearch(true);
|
$collector->setExpandGroupSearch(true);
|
||||||
|
|
||||||
$groups = $collector->getPaginatedGroups();
|
$groups = $collector->getPaginatedGroups();
|
||||||
$groups->setPath(route('accounts.show.all', [$account->id]));
|
$groups->setPath(route('accounts.show.all', [$account->id]));
|
||||||
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||||
$showAll = true;
|
$showAll = true;
|
||||||
// correct
|
// correct
|
||||||
Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
|
Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
|
||||||
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
|
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency);
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'accounts.show',
|
'accounts.show',
|
||||||
|
@@ -52,8 +52,8 @@ class AcceptHeaders
|
|||||||
// if bad 'Content-Type' header, refuse service.
|
// if bad 'Content-Type' header, refuse service.
|
||||||
|
|
||||||
// some routes are exempt from this.
|
// some routes are exempt from this.
|
||||||
$exempt = [
|
$exempt = [
|
||||||
'api.v1.data.bulk.transactions'
|
'api.v1.data.bulk.transactions',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (('POST' === $method || 'PUT' === $method) && !$request->hasHeader('Content-Type') && !in_array($request->route()->getName(), $exempt, true)) {
|
if (('POST' === $method || 'PUT' === $method) && !$request->hasHeader('Content-Type') && !in_array($request->route()->getName(), $exempt, true)) {
|
||||||
|
@@ -45,7 +45,6 @@ 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.
|
||||||
@@ -76,7 +75,8 @@ 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);
|
||||||
@@ -85,7 +85,8 @@ 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);
|
||||||
@@ -111,7 +112,8 @@ 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');
|
||||||
@@ -138,7 +140,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');
|
||||||
@@ -160,7 +162,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
|
|||||||
return $account;
|
return $account;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[\Override]
|
||||||
public function getAccountBalances(Account $account): Collection
|
public function getAccountBalances(Account $account): Collection
|
||||||
{
|
{
|
||||||
return $account->accountBalances;
|
return $account->accountBalances;
|
||||||
@@ -192,10 +194,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)) {
|
||||||
@@ -211,7 +213,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');
|
||||||
@@ -233,7 +235,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);
|
||||||
@@ -245,9 +247,10 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -256,9 +259,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)) {
|
||||||
@@ -291,10 +294,11 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -315,9 +319,10 @@ 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
|
||||||
@@ -330,9 +335,10 @@ 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
|
||||||
@@ -352,18 +358,19 @@ 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,
|
||||||
@@ -373,7 +380,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);
|
||||||
@@ -381,8 +388,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)) {
|
||||||
@@ -446,7 +453,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],
|
||||||
@@ -462,7 +469,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;
|
||||||
@@ -513,12 +520,13 @@ 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);
|
||||||
@@ -554,10 +562,11 @@ 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])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -574,11 +583,12 @@ 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);
|
||||||
@@ -598,12 +608,13 @@ 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);
|
||||||
@@ -642,15 +653,16 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
|
|||||||
return $factory->create($data);
|
return $factory->create($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[\Override] public function periodCollection(Account $account, Carbon $start, Carbon $end): array
|
#[\Override]
|
||||||
|
public function periodCollection(Account $account, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
return $account->transactions()
|
return $account->transactions()
|
||||||
->leftJoin('transaction_journals','transaction_journals.id','=','transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_types','transaction_types.id','=','transaction_journals.transaction_type_id')
|
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||||
->leftJoin('transaction_currencies','transaction_currencies.id','=','transactions.transaction_currency_id')
|
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
||||||
->leftJoin('transaction_currencies as foreign_currencies','foreign_currencies.id','=','transactions.foreign_currency_id')
|
->leftJoin('transaction_currencies as foreign_currencies', 'foreign_currencies.id', '=', 'transactions.foreign_currency_id')
|
||||||
->where('transaction_journals.date','>=',$start)
|
->where('transaction_journals.date', '>=', $start)
|
||||||
->where('transaction_journals.date','<=',$end)
|
->where('transaction_journals.date', '<=', $end)
|
||||||
->get([
|
->get([
|
||||||
// currencies
|
// currencies
|
||||||
'transaction_currencies.id as currency_id',
|
'transaction_currencies.id as currency_id',
|
||||||
@@ -667,7 +679,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
|
|||||||
'foreign_currencies.decimal_places as foreign_decimal_places',
|
'foreign_currencies.decimal_places as foreign_decimal_places',
|
||||||
|
|
||||||
// fields
|
// fields
|
||||||
'transaction_journals.date', 'transaction_types.type', 'transaction_journals.transaction_currency_id', 'transactions.amount'])
|
'transaction_journals.date', 'transaction_types.type', 'transaction_journals.transaction_currency_id', 'transactions.amount'])
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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'],
|
||||||
|
@@ -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,8 +123,7 @@ 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');
|
||||||
@@ -141,8 +140,7 @@ 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();
|
||||||
|
|
||||||
@@ -175,14 +173,15 @@ 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);
|
||||||
@@ -200,10 +199,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;
|
||||||
@@ -225,8 +224,7 @@ 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');
|
||||||
@@ -248,8 +246,7 @@ 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');
|
||||||
@@ -264,8 +261,7 @@ 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');
|
||||||
@@ -280,8 +276,7 @@ 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');
|
||||||
@@ -296,8 +291,7 @@ 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');
|
||||||
@@ -318,7 +312,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'];
|
||||||
@@ -331,12 +325,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] ??= [
|
||||||
@@ -353,7 +347,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',
|
||||||
@@ -371,15 +365,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
|
||||||
@@ -397,7 +391,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',
|
||||||
@@ -414,8 +408,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;
|
||||||
|
@@ -23,7 +23,6 @@ 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;
|
||||||
@@ -36,7 +35,6 @@ 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.
|
||||||
@@ -46,14 +44,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);
|
||||||
@@ -120,7 +118,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.');
|
||||||
}
|
}
|
||||||
@@ -160,14 +158,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);
|
||||||
|
@@ -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']);
|
||||||
|
@@ -62,7 +62,8 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,8 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -176,9 +178,10 @@ 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
|
||||||
@@ -202,24 +205,25 @@ 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)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,7 +248,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
|
||||||
@@ -257,7 +261,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,
|
||||||
@@ -292,8 +296,9 @@ 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)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -306,13 +311,14 @@ 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',
|
||||||
]
|
]
|
||||||
);
|
)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,10 +327,11 @@ 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.*'])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -335,15 +342,16 @@ 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 = [];
|
||||||
@@ -357,27 +365,28 @@ 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,
|
||||||
@@ -427,7 +436,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);
|
||||||
@@ -435,17 +444,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.
|
||||||
@@ -457,8 +466,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);
|
||||||
|
|
||||||
@@ -519,8 +528,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,
|
||||||
@@ -529,7 +538,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) {
|
||||||
@@ -546,10 +555,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
|
||||||
@@ -563,9 +572,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());
|
||||||
|
|
||||||
@@ -574,10 +583,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,
|
||||||
@@ -615,7 +624,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;
|
||||||
|
@@ -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,21 +105,23 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -132,14 +134,15 @@ 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) {
|
||||||
@@ -184,9 +187,10 @@ 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
|
||||||
@@ -196,7 +200,8 @@ 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()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,12 +210,13 @@ 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();
|
||||||
@@ -230,7 +236,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();
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,6 @@ 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 Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BudgetLimitRepository
|
* Class BudgetLimitRepository
|
||||||
@@ -51,10 +50,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,27 +63,30 @@ 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());
|
||||||
}
|
}
|
||||||
@@ -136,17 +138,19 @@ 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'));
|
||||||
@@ -161,36 +165,39 @@ 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(
|
)
|
||||||
static function (Builder $q4) use ($start, $end): void {
|
->orWhere(
|
||||||
// or start is before start AND end is after end.
|
static function (Builder $q4) use ($start, $end): void {
|
||||||
$q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d'));
|
// or start is before start AND end is after end.
|
||||||
$q4->where('budget_limits.end_date', '>=', $end->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'));
|
||||||
);
|
}
|
||||||
}
|
)
|
||||||
)->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
|
||||||
@@ -215,38 +222,41 @@ 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(
|
)
|
||||||
static function (Builder $q4) use ($start, $end): void {
|
->orWhere(
|
||||||
// or start is before start AND end is after end.
|
static function (Builder $q4) use ($start, $end): void {
|
||||||
$q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 23:59:59'));
|
// or start is before start AND end is after end.
|
||||||
$q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d 00:00:00'));
|
$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'));
|
||||||
);
|
}
|
||||||
}
|
)
|
||||||
)->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;
|
||||||
@@ -259,34 +269,35 @@ 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');
|
||||||
@@ -294,7 +305,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);
|
||||||
}
|
}
|
||||||
@@ -308,12 +319,13 @@ 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();
|
||||||
@@ -335,8 +347,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();
|
||||||
@@ -348,7 +360,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)) {
|
||||||
@@ -360,7 +372,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;
|
||||||
@@ -377,26 +389,29 @@ 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.
|
||||||
@@ -418,7 +433,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');
|
||||||
|
@@ -63,7 +63,8 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -75,7 +76,8 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -83,7 +85,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);
|
||||||
@@ -100,9 +102,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,
|
||||||
@@ -157,9 +159,10 @@ 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()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,19 +202,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,
|
||||||
@@ -280,7 +283,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);
|
||||||
@@ -295,7 +298,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;
|
||||||
@@ -321,10 +324,11 @@ 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 */
|
||||||
@@ -339,10 +343,11 @@ 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 */
|
||||||
@@ -386,7 +391,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.
|
||||||
@@ -466,7 +471,8 @@ 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
|
||||||
@@ -524,7 +530,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');
|
||||||
|
|
||||||
@@ -550,8 +556,9 @@ 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
|
||||||
@@ -571,7 +578,8 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -591,8 +599,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) {
|
||||||
@@ -603,19 +611,20 @@ 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'],
|
||||||
@@ -626,9 +635,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'],
|
||||||
@@ -652,8 +661,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) {
|
||||||
@@ -664,19 +673,20 @@ 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'],
|
||||||
@@ -687,9 +697,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'],
|
||||||
@@ -711,7 +721,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(
|
||||||
@@ -738,7 +748,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;
|
||||||
}
|
}
|
||||||
@@ -757,8 +767,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']);
|
||||||
}
|
}
|
||||||
@@ -769,7 +779,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;
|
||||||
@@ -778,11 +788,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(
|
||||||
[
|
[
|
||||||
|
@@ -42,7 +42,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface BudgetRepositoryInterface
|
interface BudgetRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -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) {
|
||||||
|
@@ -41,7 +41,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface NoBudgetRepositoryInterface
|
interface NoBudgetRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -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,8 +202,7 @@ 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.
|
||||||
@@ -211,8 +210,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) {
|
||||||
@@ -222,11 +221,12 @@ 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) {
|
||||||
|
@@ -42,7 +42,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface OperationsRepositoryInterface
|
interface OperationsRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -24,7 +24,6 @@ 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;
|
||||||
@@ -151,7 +150,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']);
|
||||||
@@ -177,7 +176,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);
|
||||||
@@ -223,9 +222,10 @@ 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,14 +314,15 @@ 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());
|
||||||
@@ -346,7 +347,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
|
||||||
{
|
{
|
||||||
|
@@ -41,7 +41,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface CategoryRepositoryInterface
|
interface CategoryRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -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'],
|
||||||
|
@@ -40,7 +40,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface NoCategoryRepositoryInterface
|
interface NoCategoryRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -63,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) {
|
||||||
@@ -77,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'],
|
||||||
@@ -140,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) {
|
||||||
@@ -154,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'],
|
||||||
@@ -193,7 +193,8 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -201,13 +202,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) {
|
||||||
@@ -215,7 +216,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'],
|
||||||
@@ -255,7 +256,8 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -263,13 +265,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) {
|
||||||
@@ -277,7 +279,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'],
|
||||||
@@ -318,7 +320,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) {
|
||||||
@@ -341,9 +343,10 @@ 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);
|
||||||
@@ -359,12 +362,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']) {
|
||||||
@@ -389,7 +392,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,
|
||||||
@@ -411,7 +414,8 @@ 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);
|
||||||
@@ -420,12 +424,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'],
|
||||||
|
@@ -40,7 +40,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface OperationsRepositoryInterface
|
interface OperationsRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -42,7 +42,6 @@ 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\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class CurrencyRepository.
|
* Class CurrencyRepository.
|
||||||
@@ -67,7 +66,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
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));
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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));
|
||||||
|
|
||||||
@@ -90,7 +89,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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));
|
||||||
|
|
||||||
@@ -98,7 +97,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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));
|
||||||
|
|
||||||
@@ -116,9 +115,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 +134,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 +142,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 +150,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.');
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[\Override]
|
||||||
public function find(int $currencyId): ?TransactionCurrency
|
public function find(int $currencyId): ?TransactionCurrency
|
||||||
{
|
{
|
||||||
return TransactionCurrency::find($currencyId);
|
return TransactionCurrency::find($currencyId);
|
||||||
@@ -320,9 +320,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
|
|||||||
|
|
||||||
/** @var null|CurrencyExchangeRate $rate */
|
/** @var null|CurrencyExchangeRate $rate */
|
||||||
$rate = $this->user->currencyExchangeRates()
|
$rate = $this->user->currencyExchangeRates()
|
||||||
->where('from_currency_id', $fromCurrency->id)
|
->where('from_currency_id', $fromCurrency->id)
|
||||||
->where('to_currency_id', $toCurrency->id)
|
->where('to_currency_id', $toCurrency->id)
|
||||||
->where('date', $date->format('Y-m-d'))->first();
|
->where('date', $date->format('Y-m-d'))->first()
|
||||||
|
;
|
||||||
if (null !== $rate) {
|
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')));
|
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')));
|
||||||
|
|
||||||
|
@@ -42,7 +42,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface CurrencyRepositoryInterface
|
interface CurrencyRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExchangeRateRepository.php
|
* ExchangeRateRepository.php
|
||||||
* Copyright (c) 2025 james@firefly-iii.org.
|
* Copyright (c) 2025 james@firefly-iii.org.
|
||||||
@@ -30,57 +31,60 @@ 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();
|
||||||
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 {
|
;
|
||||||
$q->where('from_currency_id', $to->id)
|
})->orWhere(function (Builder $q) use ($from, $to): void {
|
||||||
->where('to_currency_id', $from->id);
|
$q->where('from_currency_id', $to->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();
|
||||||
@@ -96,7 +100,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;
|
||||||
@@ -107,5 +111,4 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface, UserGro
|
|||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExchangeRateRepositoryInterface.php
|
* ExchangeRateRepositoryInterface.php
|
||||||
* Copyright (c) 2025 james@firefly-iii.org.
|
* Copyright (c) 2025 james@firefly-iii.org.
|
||||||
@@ -32,7 +33,6 @@ use FireflyIII\User;
|
|||||||
use Illuminate\Contracts\Auth\Authenticatable;
|
use Illuminate\Contracts\Auth\Authenticatable;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface ExchangeRateRepositoryInterface
|
* Interface ExchangeRateRepositoryInterface
|
||||||
*
|
*
|
||||||
|
@@ -47,9 +47,10 @@ 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.*'])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,7 +60,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');
|
||||||
|
|
||||||
|
@@ -41,7 +41,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface JournalAPIRepositoryInterface
|
interface JournalAPIRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -32,7 +32,6 @@ 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
|
||||||
@@ -47,9 +46,10 @@ 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,11 +179,12 @@ 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;
|
||||||
@@ -192,7 +193,8 @@ 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()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -67,7 +67,8 @@ 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.*'])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,7 +102,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()) {
|
||||||
@@ -150,7 +151,8 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -193,7 +195,8 @@ 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));
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface JournalRepositoryInterface
|
interface JournalRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,6 @@ 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;
|
||||||
@@ -72,7 +71,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function destroyLink(TransactionJournalLink $link): bool
|
public function destroyLink(TransactionJournalLink $link): bool
|
||||||
{
|
{
|
||||||
@@ -117,12 +116,13 @@ 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,12 +233,13 @@ 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
|
||||||
{
|
{
|
||||||
@@ -280,7 +281,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
|
||||||
{
|
{
|
||||||
@@ -296,7 +297,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']);
|
||||||
|
@@ -41,7 +41,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface LinkTypeRepositoryInterface
|
interface LinkTypeRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -53,9 +53,10 @@ 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
|
||||||
@@ -148,16 +149,18 @@ 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();
|
||||||
|
@@ -40,7 +40,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface ObjectGroupRepositoryInterface
|
interface ObjectGroupRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -24,7 +24,6 @@ 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;
|
||||||
@@ -69,9 +68,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);
|
||||||
}
|
}
|
||||||
@@ -92,9 +91,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);
|
||||||
}
|
}
|
||||||
@@ -126,8 +125,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)));
|
||||||
|
|
||||||
@@ -142,7 +141,7 @@ trait ModifiesPiggyBanks
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function destroy(PiggyBank $piggyBank): bool
|
public function destroy(PiggyBank $piggyBank): bool
|
||||||
{
|
{
|
||||||
@@ -161,11 +160,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;
|
||||||
}
|
}
|
||||||
@@ -208,14 +207,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);
|
||||||
}
|
}
|
||||||
@@ -308,7 +307,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);
|
||||||
@@ -319,15 +318,16 @@ 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,11 +336,12 @@ 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));
|
||||||
@@ -361,7 +362,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,6 @@ 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.
|
||||||
@@ -57,9 +56,10 @@ 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,9 +90,10 @@ 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.*'])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,14 +102,15 @@ 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');
|
||||||
|
|
||||||
@@ -155,15 +157,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);
|
||||||
@@ -171,11 +173,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:
|
||||||
@@ -207,7 +209,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
|
||||||
@@ -223,9 +225,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.
|
||||||
@@ -306,20 +308,23 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
|
|||||||
public function getPiggyBanks(): Collection
|
public function getPiggyBanks(): Collection
|
||||||
{
|
{
|
||||||
$query = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
|
$query = 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')
|
||||||
|
;
|
||||||
if (null === $this->user) {
|
if (null === $this->user) {
|
||||||
$query->where('accounts.user_group_id', $this->userGroup->id);
|
$query->where('accounts.user_group_id', $this->userGroup->id);
|
||||||
}
|
}
|
||||||
if (null !== $this->user) {
|
if (null !== $this->user) {
|
||||||
$query->where('accounts.user_id', $this->user->id);
|
$query->where('accounts.user_id', $this->user->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query
|
return $query
|
||||||
->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
|
||||||
@@ -385,23 +390,24 @@ 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();
|
||||||
@@ -412,19 +418,21 @@ 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.*']);
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface PiggyBankRepositoryInterface
|
interface PiggyBankRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -67,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) {
|
||||||
@@ -79,8 +79,9 @@ 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));
|
||||||
|
|
||||||
@@ -97,11 +98,12 @@ 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()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,9 +129,10 @@ 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
|
||||||
@@ -204,10 +207,11 @@ 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'));
|
||||||
}
|
}
|
||||||
@@ -226,10 +230,11 @@ 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()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,22 +282,24 @@ 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();
|
||||||
@@ -301,11 +308,12 @@ 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) {
|
||||||
@@ -316,7 +324,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();
|
||||||
@@ -459,21 +467,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);
|
||||||
}
|
}
|
||||||
@@ -488,7 +496,8 @@ 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']);
|
||||||
}
|
}
|
||||||
@@ -534,7 +543,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')));
|
||||||
|
|
||||||
|
@@ -45,7 +45,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface RecurringRepositoryInterface
|
interface RecurringRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,6 @@ 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;
|
||||||
@@ -43,7 +42,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
|
||||||
{
|
{
|
||||||
@@ -112,7 +111,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;
|
||||||
@@ -142,7 +141,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);
|
||||||
}
|
}
|
||||||
@@ -161,13 +160,14 @@ 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,13 +186,14 @@ 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 */
|
||||||
@@ -215,7 +216,8 @@ 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']);
|
||||||
}
|
}
|
||||||
@@ -225,7 +227,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']);
|
||||||
}
|
}
|
||||||
@@ -239,7 +241,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);
|
||||||
|
|
||||||
@@ -283,7 +285,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();
|
||||||
@@ -311,19 +313,20 @@ 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();
|
||||||
@@ -332,11 +335,12 @@ 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();
|
||||||
@@ -361,7 +365,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',
|
||||||
@@ -388,7 +392,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
|
|||||||
$value = '';
|
$value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$triggerValues = [
|
$triggerValues = [
|
||||||
'action' => $type,
|
'action' => $type,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'stop_processing' => $stopProcessing,
|
'stop_processing' => $stopProcessing,
|
||||||
@@ -402,7 +406,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'];
|
||||||
@@ -435,7 +439,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'];
|
||||||
@@ -465,7 +469,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)) {
|
||||||
|
@@ -42,7 +42,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface RuleRepositoryInterface
|
interface RuleRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,6 @@ 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;
|
||||||
@@ -48,7 +47,8 @@ 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,7 +105,8 @@ 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 */
|
||||||
@@ -127,10 +128,11 @@ 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 */
|
||||||
@@ -152,10 +154,11 @@ 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 */
|
||||||
@@ -172,10 +175,11 @@ 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 */
|
||||||
@@ -222,47 +226,51 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -303,21 +311,22 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -351,7 +360,8 @@ 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
|
||||||
@@ -366,7 +376,8 @@ 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']);
|
||||||
}
|
}
|
||||||
@@ -394,12 +405,13 @@ 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();
|
||||||
@@ -408,8 +420,9 @@ 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();
|
||||||
|
@@ -39,7 +39,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface RuleGroupRepositoryInterface
|
interface RuleGroupRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -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' => [],
|
||||||
|
@@ -40,7 +40,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface OperationsRepositoryInterface
|
interface OperationsRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -24,7 +24,6 @@ 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;
|
||||||
@@ -52,7 +51,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function destroy(Tag $tag): bool
|
public function destroy(Tag $tag): bool
|
||||||
{
|
{
|
||||||
@@ -120,7 +119,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;
|
||||||
@@ -131,7 +130,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) {
|
||||||
@@ -141,7 +140,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 = [];
|
||||||
@@ -236,13 +235,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) {
|
||||||
@@ -253,7 +252,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'],
|
||||||
@@ -267,14 +266,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,
|
||||||
@@ -288,7 +287,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');
|
||||||
}
|
}
|
||||||
@@ -353,7 +352,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);
|
||||||
|
@@ -41,7 +41,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface TagRepositoryInterface
|
interface TagRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -25,7 +25,6 @@ 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;
|
||||||
@@ -141,21 +140,22 @@ 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,8 +171,9 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -193,13 +194,14 @@ 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.
|
||||||
@@ -263,10 +265,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));
|
||||||
}
|
}
|
||||||
@@ -289,15 +291,16 @@ 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) {
|
||||||
@@ -313,10 +316,11 @@ 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) {
|
||||||
@@ -337,8 +341,9 @@ 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) {
|
||||||
@@ -346,13 +351,14 @@ 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][] = [
|
||||||
@@ -379,10 +385,11 @@ 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();
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface TransactionGroupRepositoryInterface
|
interface TransactionGroupRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface TransactionTypeRepositoryInterface
|
interface TransactionTypeRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,6 @@ 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;
|
||||||
@@ -35,7 +34,6 @@ 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.
|
||||||
@@ -46,17 +44,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)));
|
||||||
@@ -101,7 +99,7 @@ class UserRepository implements UserRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function destroy(User $user): bool
|
public function destroy(User $user): bool
|
||||||
{
|
{
|
||||||
@@ -173,7 +171,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));
|
||||||
}
|
}
|
||||||
@@ -199,7 +197,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;
|
||||||
@@ -215,11 +213,12 @@ 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();
|
||||||
@@ -227,7 +226,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;
|
||||||
@@ -244,7 +243,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();
|
||||||
@@ -256,7 +255,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;
|
||||||
}
|
}
|
||||||
@@ -268,14 +267,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;
|
||||||
@@ -386,11 +385,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();
|
||||||
|
@@ -40,7 +40,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface UserRepositoryInterface
|
interface UserRepositoryInterface
|
||||||
{
|
{
|
||||||
@@ -106,9 +105,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;
|
||||||
|
|
||||||
|
@@ -35,8 +35,6 @@ 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
|
||||||
@@ -53,7 +51,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;
|
||||||
}
|
}
|
||||||
@@ -82,8 +80,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
|
||||||
@@ -110,7 +108,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;
|
||||||
}
|
}
|
||||||
@@ -135,14 +133,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;
|
||||||
}
|
}
|
||||||
@@ -163,7 +161,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);
|
||||||
}
|
}
|
||||||
@@ -178,13 +176,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();
|
||||||
@@ -194,10 +192,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);
|
||||||
@@ -223,11 +221,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']);
|
||||||
@@ -266,8 +264,9 @@ 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
|
||||||
@@ -287,7 +286,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;
|
||||||
}
|
}
|
||||||
@@ -314,7 +313,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;
|
||||||
|
@@ -39,7 +39,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface UserGroupRepositoryInterface
|
interface UserGroupRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -37,8 +37,6 @@ 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
|
||||||
@@ -49,7 +47,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();
|
||||||
@@ -72,7 +70,8 @@ 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');
|
||||||
@@ -99,7 +98,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');
|
||||||
@@ -121,7 +120,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;
|
||||||
@@ -129,8 +128,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)) {
|
||||||
@@ -175,12 +174,13 @@ 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,22 +258,23 @@ 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 */
|
||||||
@@ -311,17 +312,18 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -368,7 +370,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 */
|
||||||
@@ -381,12 +383,13 @@ 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)) {
|
||||||
|
@@ -73,7 +73,6 @@ interface AccountRepositoryInterface
|
|||||||
|
|
||||||
public function getObjectGroups(Collection $accounts): array;
|
public function getObjectGroups(Collection $accounts): array;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset order types of the mentioned accounts.
|
* Reset order types of the mentioned accounts.
|
||||||
*/
|
*/
|
||||||
|
@@ -62,8 +62,9 @@ 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
|
||||||
@@ -101,13 +102,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);
|
||||||
@@ -129,9 +130,10 @@ 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
|
||||||
@@ -153,7 +155,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,
|
||||||
@@ -200,7 +202,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;
|
||||||
|
@@ -46,13 +46,14 @@ 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,
|
||||||
|
@@ -39,16 +39,18 @@ 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()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -59,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) {
|
||||||
@@ -73,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'],
|
||||||
@@ -91,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,
|
||||||
|
@@ -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,9 +115,10 @@ 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));
|
||||||
|
|
||||||
@@ -133,7 +134,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));
|
||||||
|
|
||||||
@@ -141,7 +142,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.');
|
||||||
|
|
||||||
@@ -149,7 +150,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.');
|
||||||
|
|
||||||
|
@@ -30,7 +30,6 @@ 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
|
||||||
@@ -41,51 +40,55 @@ 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 {
|
;
|
||||||
$q->where('from_currency_id', $to->id)
|
})->orWhere(function (Builder $q) use ($from, $to): void {
|
||||||
->where('to_currency_id', $from->id);
|
$q->where('from_currency_id', $to->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();
|
||||||
@@ -101,7 +104,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;
|
||||||
|
@@ -40,7 +40,8 @@ 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 {
|
||||||
|
@@ -40,13 +40,14 @@ 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.*'])
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,21 +67,23 @@ 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
|
||||||
|
@@ -42,7 +42,6 @@ use Illuminate\Support\Collection;
|
|||||||
* @method checkUserGroupAccess(UserRoleEnum $role)
|
* @method checkUserGroupAccess(UserRoleEnum $role)
|
||||||
* @method setUser(null|Authenticatable|User $user)
|
* @method setUser(null|Authenticatable|User $user)
|
||||||
* @method setUserGroupById(int $userGroupId)
|
* @method setUserGroupById(int $userGroupId)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface WebhookRepositoryInterface
|
interface WebhookRepositoryInterface
|
||||||
{
|
{
|
||||||
|
@@ -31,6 +31,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
|
|
||||||
class IsValidZeroOrMoreAmount implements ValidationRule
|
class IsValidZeroOrMoreAmount implements ValidationRule
|
||||||
{
|
{
|
||||||
|
use ValidatesAmountsTrait;
|
||||||
private bool $nullable = false;
|
private bool $nullable = false;
|
||||||
|
|
||||||
public function __construct(bool $nullable = false)
|
public function __construct(bool $nullable = false)
|
||||||
@@ -38,9 +39,6 @@ class IsValidZeroOrMoreAmount implements ValidationRule
|
|||||||
$this->nullable = $nullable;
|
$this->nullable = $nullable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
use ValidatesAmountsTrait;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||||
*/
|
*/
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timer.php
|
* Timer.php
|
||||||
* Copyright (c) 2025 james@firefly-iii.org.
|
* Copyright (c) 2025 james@firefly-iii.org.
|
||||||
@@ -42,5 +43,4 @@ class Timer
|
|||||||
unset(self::$times[$title]);
|
unset(self::$times[$title]);
|
||||||
Log::debug(sprintf('Timer "%s" took %f seconds', $title, $diff));
|
Log::debug(sprintf('Timer "%s" took %f seconds', $title, $diff));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,6 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
|||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use FireflyIII\Support\Debug\Timer;
|
use FireflyIII\Support\Debug\Timer;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait PeriodOverview.
|
* Trait PeriodOverview.
|
||||||
@@ -82,10 +81,10 @@ trait PeriodOverview
|
|||||||
Timer::start('account-period-total');
|
Timer::start('account-period-total');
|
||||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||||
$range = app('navigation')->getViewRange(true);
|
$range = app('navigation')->getViewRange(true);
|
||||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||||
|
|
||||||
// properties for cache
|
// properties for cache
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('account-show-period-entries');
|
$cache->addProperty('account-show-period-entries');
|
||||||
@@ -95,38 +94,40 @@ trait PeriodOverview
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var array $dates */
|
/** @var array $dates */
|
||||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
// run a custom query because doing this with the collector is MEGA slow.
|
// run a custom query because doing this with the collector is MEGA slow.
|
||||||
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
|
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
|
||||||
|
|
||||||
// loop dates
|
// loop dates
|
||||||
foreach ($dates as $currentDate) {
|
foreach ($dates as $currentDate) {
|
||||||
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
|
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
|
||||||
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
|
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
|
||||||
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
|
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
|
||||||
[$transactions, $transferredAway] = $this->filterTransfers('away',$transactions, $currentDate['start'], $currentDate['end']);
|
[$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']);
|
||||||
[$transactions, $transferredIn] = $this->filterTransfers('in',$transactions, $currentDate['start'], $currentDate['end']);
|
[$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']);
|
||||||
$entries[]
|
$entries[]
|
||||||
= [
|
= [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
||||||
'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn),
|
'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn),
|
||||||
'spent' => $this->groupByCurrency($spent),
|
'spent' => $this->groupByCurrency($spent),
|
||||||
'earned' => $this->groupByCurrency($earned),
|
'earned' => $this->groupByCurrency($earned),
|
||||||
'transferred_away' => $this->groupByCurrency($transferredAway),
|
'transferred_away' => $this->groupByCurrency($transferredAway),
|
||||||
'transferred_in' => $this->groupByCurrency($transferredIn),
|
'transferred_in' => $this->groupByCurrency($transferredIn),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$cache->store($entries);
|
$cache->store($entries);
|
||||||
Timer::stop('account-period-total');
|
Timer::stop('account-period-total');
|
||||||
|
|
||||||
return $entries;
|
return $entries;
|
||||||
}
|
}
|
||||||
private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array
|
|
||||||
|
private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int $index
|
* @var int $index
|
||||||
* @var array $item
|
* @var array $item
|
||||||
@@ -134,29 +135,31 @@ trait PeriodOverview
|
|||||||
foreach ($transactions as $index => $item) {
|
foreach ($transactions as $index => $item) {
|
||||||
$date = Carbon::parse($item['date']);
|
$date = Carbon::parse($item['date']);
|
||||||
if ($date >= $start && $date <= $end) {
|
if ($date >= $start && $date <= $end) {
|
||||||
if ($direction === 'away' && bccomp($item['amount'], '0') === -1) {
|
if ('away' === $direction && -1 === bccomp($item['amount'], '0')) {
|
||||||
$result[] = $item;
|
$result[] = $item;
|
||||||
unset($transactions[$index]);
|
unset($transactions[$index]);
|
||||||
}
|
}
|
||||||
if ($direction === 'in' && bccomp($item['amount'], '0') === 1) {
|
if ('in' === $direction && 1 === bccomp($item['amount'], '0')) {
|
||||||
$result[] = $item;
|
$result[] = $item;
|
||||||
unset($transactions[$index]);
|
unset($transactions[$index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [$transactions, $result];
|
return [$transactions, $result];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array
|
private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int $index
|
* @var int $index
|
||||||
* @var array $item
|
* @var array $item
|
||||||
*/
|
*/
|
||||||
foreach ($transactions as $index => $item) {
|
foreach ($transactions as $index => $item) {
|
||||||
$date = Carbon::parse($item['date']);
|
$date = Carbon::parse($item['date']);
|
||||||
if($item['type'] === $type->value && $date >= $start && $date <= $end) {
|
if ($item['type'] === $type->value && $date >= $start && $date <= $end) {
|
||||||
$result[] = $item;
|
$result[] = $item;
|
||||||
unset($transactions[$index]);
|
unset($transactions[$index]);
|
||||||
}
|
}
|
||||||
@@ -222,13 +225,13 @@ trait PeriodOverview
|
|||||||
|
|
||||||
/** @var array $journal */
|
/** @var array $journal */
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$currencyId = (int) $journal['currency_id'];
|
$currencyId = (int) $journal['currency_id'];
|
||||||
$currencyCode = $journal['currency_code'];
|
$currencyCode = $journal['currency_code'];
|
||||||
$currencyName = $journal['currency_name'];
|
$currencyName = $journal['currency_name'];
|
||||||
$currencySymbol = $journal['currency_symbol'];
|
$currencySymbol = $journal['currency_symbol'];
|
||||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||||
$foreignCurrencyId = $journal['foreign_currency_id'];
|
$foreignCurrencyId = $journal['foreign_currency_id'];
|
||||||
$amount = $journal['amount'] ?? '0';
|
$amount = $journal['amount'] ?? '0';
|
||||||
|
|
||||||
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) {
|
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) {
|
||||||
$amount = $journal['native_amount'] ?? '0';
|
$amount = $journal['native_amount'] ?? '0';
|
||||||
@@ -271,11 +274,11 @@ trait PeriodOverview
|
|||||||
*/
|
*/
|
||||||
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
|
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$range = app('navigation')->getViewRange(true);
|
$range = app('navigation')->getViewRange(true);
|
||||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||||
|
|
||||||
// properties for entries with their amounts.
|
// properties for entries with their amounts.
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($range);
|
$cache->addProperty($range);
|
||||||
@@ -287,32 +290,32 @@ trait PeriodOverview
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var array $dates */
|
/** @var array $dates */
|
||||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
// collect all expenses in this period:
|
// collect all expenses in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setCategory($category);
|
$collector->setCategory($category);
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
||||||
$earnedSet = $collector->getExtractedJournals();
|
$earnedSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// collect all income in this period:
|
// collect all income in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setCategory($category);
|
$collector->setCategory($category);
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||||
$spentSet = $collector->getExtractedJournals();
|
$spentSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// collect all transfers in this period:
|
// collect all transfers in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setCategory($category);
|
$collector->setCategory($category);
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::TRANSFER->value]);
|
$collector->setTypes([TransactionTypeEnum::TRANSFER->value]);
|
||||||
$transferSet = $collector->getExtractedJournals();
|
$transferSet = $collector->getExtractedJournals();
|
||||||
foreach ($dates as $currentDate) {
|
foreach ($dates as $currentDate) {
|
||||||
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
||||||
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
|
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
|
||||||
@@ -320,17 +323,17 @@ trait PeriodOverview
|
|||||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||||
$entries[]
|
$entries[]
|
||||||
= [
|
= [
|
||||||
'transactions' => 0,
|
'transactions' => 0,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'route' => route(
|
'route' => route(
|
||||||
'categories.show',
|
'categories.show',
|
||||||
[$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
|
[$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
|
||||||
),
|
),
|
||||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||||
'spent' => $this->groupByCurrency($spent),
|
'spent' => $this->groupByCurrency($spent),
|
||||||
'earned' => $this->groupByCurrency($earned),
|
'earned' => $this->groupByCurrency($earned),
|
||||||
'transferred' => $this->groupByCurrency($transferred),
|
'transferred' => $this->groupByCurrency($transferred),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$cache->store($entries);
|
$cache->store($entries);
|
||||||
|
|
||||||
@@ -346,11 +349,11 @@ trait PeriodOverview
|
|||||||
*/
|
*/
|
||||||
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
|
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$range = app('navigation')->getViewRange(true);
|
$range = app('navigation')->getViewRange(true);
|
||||||
|
|
||||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||||
|
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($this->convertToNative);
|
$cache->addProperty($this->convertToNative);
|
||||||
@@ -361,28 +364,28 @@ trait PeriodOverview
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var array $dates */
|
/** @var array $dates */
|
||||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
// get all expenses without a budget.
|
// get all expenses without a budget.
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setRange($start, $end)->withoutBudget()->withAccountInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
$collector->setRange($start, $end)->withoutBudget()->withAccountInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
|
|
||||||
foreach ($dates as $currentDate) {
|
foreach ($dates as $currentDate) {
|
||||||
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
|
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
|
||||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||||
$entries[]
|
$entries[]
|
||||||
= [
|
= [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
||||||
'total_transactions' => count($set),
|
'total_transactions' => count($set),
|
||||||
'spent' => $this->groupByCurrency($set),
|
'spent' => $this->groupByCurrency($set),
|
||||||
'earned' => [],
|
'earned' => [],
|
||||||
'transferred_away' => [],
|
'transferred_away' => [],
|
||||||
'transferred_in' => [],
|
'transferred_in' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$cache->store($entries);
|
$cache->store($entries);
|
||||||
|
|
||||||
@@ -399,38 +402,38 @@ trait PeriodOverview
|
|||||||
protected function getNoCategoryPeriodOverview(Carbon $theDate): array
|
protected function getNoCategoryPeriodOverview(Carbon $theDate): array
|
||||||
{
|
{
|
||||||
app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
|
app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
|
||||||
$range = app('navigation')->getViewRange(true);
|
$range = app('navigation')->getViewRange(true);
|
||||||
$first = $this->journalRepos->firstNull();
|
$first = $this->journalRepos->firstNull();
|
||||||
$start = null === $first ? new Carbon() : $first->date;
|
$start = null === $first ? new Carbon() : $first->date;
|
||||||
$end = clone $theDate;
|
$end = clone $theDate;
|
||||||
$end = app('navigation')->endOfPeriod($end, $range);
|
$end = app('navigation')->endOfPeriod($end, $range);
|
||||||
|
|
||||||
app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
|
app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
|
||||||
app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
|
app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
|
||||||
|
|
||||||
// properties for cache
|
// properties for cache
|
||||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
// collect all expenses in this period:
|
// collect all expenses in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->withoutCategory();
|
$collector->withoutCategory();
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
||||||
$earnedSet = $collector->getExtractedJournals();
|
$earnedSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// collect all income in this period:
|
// collect all income in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->withoutCategory();
|
$collector->withoutCategory();
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||||
$spentSet = $collector->getExtractedJournals();
|
$spentSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// collect all transfers in this period:
|
// collect all transfers in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->withoutCategory();
|
$collector->withoutCategory();
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::TRANSFER->value]);
|
$collector->setTypes([TransactionTypeEnum::TRANSFER->value]);
|
||||||
@@ -444,13 +447,13 @@ trait PeriodOverview
|
|||||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||||
$entries[]
|
$entries[]
|
||||||
= [
|
= [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
||||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||||
'spent' => $this->groupByCurrency($spent),
|
'spent' => $this->groupByCurrency($spent),
|
||||||
'earned' => $this->groupByCurrency($earned),
|
'earned' => $this->groupByCurrency($earned),
|
||||||
'transferred' => $this->groupByCurrency($transferred),
|
'transferred' => $this->groupByCurrency($transferred),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
app('log')->debug('End of loops');
|
app('log')->debug('End of loops');
|
||||||
|
|
||||||
@@ -464,11 +467,11 @@ trait PeriodOverview
|
|||||||
*/
|
*/
|
||||||
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
|
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
|
||||||
{
|
{
|
||||||
$range = app('navigation')->getViewRange(true);
|
$range = app('navigation')->getViewRange(true);
|
||||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||||
|
|
||||||
// properties for cache
|
// properties for cache
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('tag-period-entries');
|
$cache->addProperty('tag-period-entries');
|
||||||
@@ -478,37 +481,37 @@ trait PeriodOverview
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var array $dates */
|
/** @var array $dates */
|
||||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
// collect all expenses in this period:
|
// collect all expenses in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setTag($tag);
|
$collector->setTag($tag);
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
||||||
$earnedSet = $collector->getExtractedJournals();
|
$earnedSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// collect all income in this period:
|
// collect all income in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setTag($tag);
|
$collector->setTag($tag);
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||||
$spentSet = $collector->getExtractedJournals();
|
$spentSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// collect all transfers in this period:
|
// collect all transfers in this period:
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setTag($tag);
|
$collector->setTag($tag);
|
||||||
$collector->setRange($start, $end);
|
$collector->setRange($start, $end);
|
||||||
$collector->setTypes([TransactionTypeEnum::TRANSFER->value]);
|
$collector->setTypes([TransactionTypeEnum::TRANSFER->value]);
|
||||||
$transferSet = $collector->getExtractedJournals();
|
$transferSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
// filer all of them:
|
// filer all of them:
|
||||||
$earnedSet = $this->filterJournalsByTag($earnedSet, $tag);
|
$earnedSet = $this->filterJournalsByTag($earnedSet, $tag);
|
||||||
$spentSet = $this->filterJournalsByTag($spentSet, $tag);
|
$spentSet = $this->filterJournalsByTag($spentSet, $tag);
|
||||||
$transferSet = $this->filterJournalsByTag($transferSet, $tag);
|
$transferSet = $this->filterJournalsByTag($transferSet, $tag);
|
||||||
|
|
||||||
foreach ($dates as $currentDate) {
|
foreach ($dates as $currentDate) {
|
||||||
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
||||||
@@ -517,17 +520,17 @@ trait PeriodOverview
|
|||||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||||
$entries[]
|
$entries[]
|
||||||
= [
|
= [
|
||||||
'transactions' => 0,
|
'transactions' => 0,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'route' => route(
|
'route' => route(
|
||||||
'tags.show',
|
'tags.show',
|
||||||
[$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
|
[$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
|
||||||
),
|
),
|
||||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||||
'spent' => $this->groupByCurrency($spent),
|
'spent' => $this->groupByCurrency($spent),
|
||||||
'earned' => $this->groupByCurrency($earned),
|
'earned' => $this->groupByCurrency($earned),
|
||||||
'transferred' => $this->groupByCurrency($transferred),
|
'transferred' => $this->groupByCurrency($transferred),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entries;
|
return $entries;
|
||||||
@@ -537,7 +540,7 @@ trait PeriodOverview
|
|||||||
{
|
{
|
||||||
$return = [];
|
$return = [];
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$found = false;
|
$found = false;
|
||||||
|
|
||||||
/** @var array $localTag */
|
/** @var array $localTag */
|
||||||
foreach ($entry['tags'] as $localTag) {
|
foreach ($entry['tags'] as $localTag) {
|
||||||
@@ -559,12 +562,12 @@ trait PeriodOverview
|
|||||||
*/
|
*/
|
||||||
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
|
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$range = app('navigation')->getViewRange(true);
|
$range = app('navigation')->getViewRange(true);
|
||||||
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
|
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
|
||||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||||
|
|
||||||
// properties for cache
|
// properties for cache
|
||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('transactions-period-entries');
|
$cache->addProperty('transactions-period-entries');
|
||||||
@@ -574,13 +577,13 @@ trait PeriodOverview
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var array $dates */
|
/** @var array $dates */
|
||||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||||
$entries = [];
|
$entries = [];
|
||||||
|
|
||||||
// collect all journals in this period (regardless of type)
|
// collect all journals in this period (regardless of type)
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
$collector->setTypes($types)->setRange($start, $end);
|
$collector->setTypes($types)->setRange($start, $end);
|
||||||
$genericSet = $collector->getExtractedJournals();
|
$genericSet = $collector->getExtractedJournals();
|
||||||
|
|
||||||
foreach ($dates as $currentDate) {
|
foreach ($dates as $currentDate) {
|
||||||
$spent = [];
|
$spent = [];
|
||||||
@@ -599,14 +602,14 @@ trait PeriodOverview
|
|||||||
$transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
|
$transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
|
||||||
}
|
}
|
||||||
$entries[]
|
$entries[]
|
||||||
= [
|
= [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
||||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||||
'spent' => $this->groupByCurrency($spent),
|
'spent' => $this->groupByCurrency($spent),
|
||||||
'earned' => $this->groupByCurrency($earned),
|
'earned' => $this->groupByCurrency($earned),
|
||||||
'transferred' => $this->groupByCurrency($transferred),
|
'transferred' => $this->groupByCurrency($transferred),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entries;
|
return $entries;
|
||||||
|
@@ -24,7 +24,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||||
|
|
||||||
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;
|
||||||
@@ -49,7 +48,6 @@ use Illuminate\Support\Facades\Log;
|
|||||||
*/
|
*/
|
||||||
class AccountEnrichment implements EnrichmentInterface
|
class AccountEnrichment implements EnrichmentInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
private Collection $collection;
|
private Collection $collection;
|
||||||
|
|
||||||
private User $user;
|
private User $user;
|
||||||
|
@@ -72,7 +72,7 @@ class Preferences
|
|||||||
|
|
||||||
public function getForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference
|
public function getForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference
|
||||||
{
|
{
|
||||||
//Log::debug(sprintf('getForUser(#%d, "%s")', $user->id, $name));
|
// Log::debug(sprintf('getForUser(#%d, "%s")', $user->id, $name));
|
||||||
// don't care about user group ID, except for some specific preferences.
|
// don't care about user group ID, except for some specific preferences.
|
||||||
$userGroupId = $this->getUserGroupId($user, $name);
|
$userGroupId = $this->getUserGroupId($user, $name);
|
||||||
$query = Preference::where('user_id', $user->id)->where('name', $name);
|
$query = Preference::where('user_id', $user->id)->where('name', $name);
|
||||||
@@ -90,7 +90,7 @@ class Preferences
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $preference) {
|
if (null !== $preference) {
|
||||||
//Log::debug(sprintf('Found preference #%d for user #%d: %s', $preference->id, $user->id, $name));
|
// Log::debug(sprintf('Found preference #%d for user #%d: %s', $preference->id, $user->id, $name));
|
||||||
|
|
||||||
return $preference;
|
return $preference;
|
||||||
}
|
}
|
||||||
|
@@ -400,14 +400,14 @@ trait ConvertsDataTypes
|
|||||||
if (!is_array($entry)) {
|
if (!is_array($entry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$amount = null;
|
$amount = null;
|
||||||
if(array_key_exists('current_amount',$entry)) {
|
if (array_key_exists('current_amount', $entry)) {
|
||||||
$amount = $this->clearString((string) ($entry['current_amount'] ?? '0'));
|
$amount = $this->clearString((string) ($entry['current_amount'] ?? '0'));
|
||||||
if(null === $entry['current_amount']) {
|
if (null === $entry['current_amount']) {
|
||||||
$amount = null;
|
$amount = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!array_key_exists('current_amount',$entry)) {
|
if (!array_key_exists('current_amount', $entry)) {
|
||||||
$amount = null;
|
$amount = null;
|
||||||
}
|
}
|
||||||
$return[] = [
|
$return[] = [
|
||||||
|
@@ -63,13 +63,13 @@ class AccountValidator
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->createMode = false;
|
$this->createMode = false;
|
||||||
$this->destError = 'No error yet.';
|
$this->destError = 'No error yet.';
|
||||||
$this->sourceError = 'No error yet.';
|
$this->sourceError = 'No error yet.';
|
||||||
$this->combinations = config('firefly.source_dests');
|
$this->combinations = config('firefly.source_dests');
|
||||||
$this->source = null;
|
$this->source = null;
|
||||||
$this->destination = null;
|
$this->destination = null;
|
||||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSource(): ?Account
|
public function getSource(): ?Account
|
||||||
|
@@ -31,15 +31,15 @@ trait ValidatesBulkTransactionQuery
|
|||||||
{
|
{
|
||||||
protected function validateTransactionQuery(Validator $validator): void
|
protected function validateTransactionQuery(Validator $validator): void
|
||||||
{
|
{
|
||||||
$data = $validator->getData();
|
$data = $validator->getData();
|
||||||
// assumption is all validation has already taken place and the query key exists.
|
// assumption is all validation has already taken place and the query key exists.
|
||||||
$query =$data['query'] ?? '[]';
|
$query = $data['query'] ?? '[]';
|
||||||
$json = json_decode($query, true, 8, JSON_THROW_ON_ERROR);
|
$json = json_decode($query, true, 8, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
array_key_exists('where', $json) &&
|
array_key_exists('where', $json)
|
||||||
array_key_exists('update', $json) &&
|
&& array_key_exists('update', $json)
|
||||||
array_key_exists('account_id', $json['where']) && array_key_exists('account_id', $json['update'])
|
&& array_key_exists('account_id', $json['where']) && array_key_exists('account_id', $json['update'])
|
||||||
) {
|
) {
|
||||||
// find both accounts, must be same type.
|
// find both accounts, must be same type.
|
||||||
// already validated: belongs to this user.
|
// already validated: belongs to this user.
|
||||||
|
16
composer.lock
generated
16
composer.lock
generated
@@ -1878,16 +1878,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v11.44.1",
|
"version": "v11.44.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "0883d4175f4e2b5c299e7087ad3c74f2ce195c6d"
|
"reference": "f85216c82cbd38b66d67ebd20ea762cb3751a4b4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/0883d4175f4e2b5c299e7087ad3c74f2ce195c6d",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/f85216c82cbd38b66d67ebd20ea762cb3751a4b4",
|
||||||
"reference": "0883d4175f4e2b5c299e7087ad3c74f2ce195c6d",
|
"reference": "f85216c82cbd38b66d67ebd20ea762cb3751a4b4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2089,7 +2089,7 @@
|
|||||||
"issues": "https://github.com/laravel/framework/issues",
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
"source": "https://github.com/laravel/framework"
|
"source": "https://github.com/laravel/framework"
|
||||||
},
|
},
|
||||||
"time": "2025-03-05T15:34:10+00:00"
|
"time": "2025-03-12T14:34:30+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/passport",
|
"name": "laravel/passport",
|
||||||
@@ -12876,7 +12876,7 @@
|
|||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": [],
|
"stability-flags": {},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
@@ -12897,6 +12897,6 @@
|
|||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"ext-xmlwriter": "*"
|
"ext-xmlwriter": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
@@ -81,7 +81,7 @@ return [
|
|||||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||||
// see cer.php for exchange rates feature flag.
|
// see cer.php for exchange rates feature flag.
|
||||||
],
|
],
|
||||||
'version' => 'develop/2025-03-05',
|
'version' => 'develop/2025-03-14',
|
||||||
'api_version' => '2.1.0', // field is no longer used.
|
'api_version' => '2.1.0', // field is no longer used.
|
||||||
'db_version' => 25,
|
'db_version' => 25,
|
||||||
|
|
||||||
|
@@ -24,241 +24,241 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'operators' => [
|
'operators' => [
|
||||||
'user_action' => ['alias' => false, 'needs_context' => true],
|
'user_action' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_id' => ['alias' => false, 'needs_context' => true],
|
'account_id' => ['alias' => false, 'needs_context' => true],
|
||||||
'reconciled' => ['alias' => false, 'needs_context' => false],
|
'reconciled' => ['alias' => false, 'needs_context' => false],
|
||||||
'source_account_id' => ['alias' => false, 'needs_context' => true],
|
'source_account_id' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination_account_id' => ['alias' => false, 'needs_context' => true],
|
'destination_account_id' => ['alias' => false, 'needs_context' => true],
|
||||||
'transaction_type' => ['alias' => false, 'needs_context' => true],
|
'transaction_type' => ['alias' => false, 'needs_context' => true],
|
||||||
'type' => ['alias' => true, 'alias_for' => 'transaction_type', 'needs_context' => true],
|
'type' => ['alias' => true, 'alias_for' => 'transaction_type', 'needs_context' => true],
|
||||||
'tag_is' => ['alias' => false, 'needs_context' => true],
|
'tag_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'tag_is_not' => ['alias' => false, 'needs_context' => true],
|
'tag_is_not' => ['alias' => false, 'needs_context' => true],
|
||||||
'tag' => ['alias' => true, 'alias_for' => 'tag_is', 'needs_context' => true],
|
'tag' => ['alias' => true, 'alias_for' => 'tag_is', 'needs_context' => true],
|
||||||
'tag_contains' => ['alias' => false, 'needs_context' => true],
|
'tag_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'tag_ends' => ['alias' => false, 'needs_context' => true],
|
'tag_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'tag_starts' => ['alias' => false, 'needs_context' => true],
|
'tag_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'description_is' => ['alias' => false, 'needs_context' => true],
|
'description_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'description' => ['alias' => true, 'alias_for' => 'description_is', 'needs_context' => true],
|
'description' => ['alias' => true, 'alias_for' => 'description_is', 'needs_context' => true],
|
||||||
'description_contains' => ['alias' => false, 'needs_context' => true],
|
'description_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'description_ends' => ['alias' => false, 'needs_context' => true],
|
'description_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'description_starts' => ['alias' => false, 'needs_context' => true],
|
'description_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'notes_is' => ['alias' => false, 'needs_context' => true],
|
'notes_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'notes_are' => ['alias' => true, 'alias_for' => 'notes_is', 'needs_context' => true],
|
'notes_are' => ['alias' => true, 'alias_for' => 'notes_is', 'needs_context' => true],
|
||||||
'notes_contains' => ['alias' => false, 'needs_context' => true],
|
'notes_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'notes_contain' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
'notes_contain' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
||||||
'notes' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
'notes' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
||||||
'notes_ends' => ['alias' => false, 'needs_context' => true],
|
'notes_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'notes_end' => ['alias' => true, 'alias_for' => 'notes_ends', 'needs_context' => true],
|
'notes_end' => ['alias' => true, 'alias_for' => 'notes_ends', 'needs_context' => true],
|
||||||
'notes_starts' => ['alias' => false, 'needs_context' => true],
|
'notes_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'notes_start' => ['alias' => true, 'alias_for' => 'notes_starts', 'needs_context' => true],
|
'notes_start' => ['alias' => true, 'alias_for' => 'notes_starts', 'needs_context' => true],
|
||||||
'source_account_is' => ['alias' => false, 'needs_context' => true],
|
'source_account_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_is' => ['alias' => true, 'alias_for' => 'source_account_is', 'needs_context' => true],
|
'from_account_is' => ['alias' => true, 'alias_for' => 'source_account_is', 'needs_context' => true],
|
||||||
'source_account_contains' => ['alias' => false, 'needs_context' => true],
|
'source_account_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'source' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
'source' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||||
'from' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
'from' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||||
'from_account_contains' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
'from_account_contains' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||||
'source_account_ends' => ['alias' => false, 'needs_context' => true],
|
'source_account_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_ends' => ['alias' => true, 'alias_for' => 'source_account_ends', 'needs_context' => true],
|
'from_account_ends' => ['alias' => true, 'alias_for' => 'source_account_ends', 'needs_context' => true],
|
||||||
'source_account_starts' => ['alias' => false, 'needs_context' => true],
|
'source_account_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_starts' => ['alias' => true, 'alias_for' => 'source_account_starts', 'needs_context' => true],
|
'from_account_starts' => ['alias' => true, 'alias_for' => 'source_account_starts', 'needs_context' => true],
|
||||||
'source_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
'source_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_nr_is' => ['alias' => true, 'alias_for' => 'source_account_nr_is', 'needs_context' => true],
|
'from_account_nr_is' => ['alias' => true, 'alias_for' => 'source_account_nr_is', 'needs_context' => true],
|
||||||
'source_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
'source_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_nr_contains' => ['alias' => true, 'alias_for' => 'source_account_nr_contains', 'needs_context' => true],
|
'from_account_nr_contains' => ['alias' => true, 'alias_for' => 'source_account_nr_contains', 'needs_context' => true],
|
||||||
'source_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
'source_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_nr_ends' => ['alias' => true, 'alias_for' => 'source_account_nr_ends', 'needs_context' => true],
|
'from_account_nr_ends' => ['alias' => true, 'alias_for' => 'source_account_nr_ends', 'needs_context' => true],
|
||||||
'source_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
'source_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'from_account_nr_starts' => ['alias' => true, 'alias_for' => 'source_account_nr_starts', 'needs_context' => true],
|
'from_account_nr_starts' => ['alias' => true, 'alias_for' => 'source_account_nr_starts', 'needs_context' => true],
|
||||||
'destination_account_is' => ['alias' => false, 'needs_context' => true],
|
'destination_account_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_is' => ['alias' => true, 'alias_for' => 'destination_account_is', 'needs_context' => true],
|
'to_account_is' => ['alias' => true, 'alias_for' => 'destination_account_is', 'needs_context' => true],
|
||||||
'destination_account_contains' => ['alias' => false, 'needs_context' => true],
|
'destination_account_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
'destination' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||||
'to' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
'to' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||||
'to_account_contains' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
'to_account_contains' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||||
'destination_account_ends' => ['alias' => false, 'needs_context' => true],
|
'destination_account_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_ends' => ['alias' => true, 'alias_for' => 'destination_account_ends', 'needs_context' => true],
|
'to_account_ends' => ['alias' => true, 'alias_for' => 'destination_account_ends', 'needs_context' => true],
|
||||||
'destination_account_starts' => ['alias' => false, 'needs_context' => true],
|
'destination_account_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_starts' => ['alias' => true, 'alias_for' => 'destination_account_starts', 'needs_context' => true],
|
'to_account_starts' => ['alias' => true, 'alias_for' => 'destination_account_starts', 'needs_context' => true],
|
||||||
'destination_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
'destination_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_nr_is' => ['alias' => true, 'alias_for' => 'destination_account_nr_is', 'needs_context' => true],
|
'to_account_nr_is' => ['alias' => true, 'alias_for' => 'destination_account_nr_is', 'needs_context' => true],
|
||||||
'destination_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
'destination_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_nr_contains' => ['alias' => true, 'alias_for' => 'destination_account_nr_contains', 'needs_context' => true],
|
'to_account_nr_contains' => ['alias' => true, 'alias_for' => 'destination_account_nr_contains', 'needs_context' => true],
|
||||||
'destination_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
'destination_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_nr_ends' => ['alias' => true, 'alias_for' => 'destination_account_nr_ends', 'needs_context' => true],
|
'to_account_nr_ends' => ['alias' => true, 'alias_for' => 'destination_account_nr_ends', 'needs_context' => true],
|
||||||
'destination_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
'destination_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'to_account_nr_starts' => ['alias' => true, 'alias_for' => 'destination_account_nr_starts', 'needs_context' => true],
|
'to_account_nr_starts' => ['alias' => true, 'alias_for' => 'destination_account_nr_starts', 'needs_context' => true],
|
||||||
'account_is' => ['alias' => false, 'needs_context' => true],
|
'account_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_contains' => ['alias' => false, 'needs_context' => true],
|
'account_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_ends' => ['alias' => false, 'needs_context' => true],
|
'account_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_starts' => ['alias' => false, 'needs_context' => true],
|
'account_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_nr_is' => ['alias' => false, 'needs_context' => true],
|
'account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
'account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
'account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
'account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'category_is' => ['alias' => false, 'needs_context' => true],
|
'category_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'category_contains' => ['alias' => false, 'needs_context' => true],
|
'category_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'category' => ['alias' => true, 'alias_for' => 'category_contains', 'needs_context' => true],
|
'category' => ['alias' => true, 'alias_for' => 'category_contains', 'needs_context' => true],
|
||||||
'category_ends' => ['alias' => false, 'needs_context' => true],
|
'category_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'category_starts' => ['alias' => false, 'needs_context' => true],
|
'category_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'budget_is' => ['alias' => false, 'needs_context' => true],
|
'budget_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'budget_contains' => ['alias' => false, 'needs_context' => true],
|
'budget_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'budget' => ['alias' => true, 'alias_for' => 'budget_contains', 'needs_context' => true],
|
'budget' => ['alias' => true, 'alias_for' => 'budget_contains', 'needs_context' => true],
|
||||||
'budget_ends' => ['alias' => false, 'needs_context' => true],
|
'budget_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'budget_starts' => ['alias' => false, 'needs_context' => true],
|
'budget_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'bill_is' => ['alias' => false, 'needs_context' => true],
|
'bill_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'bill_contains' => ['alias' => false, 'needs_context' => true],
|
'bill_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'bill' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
'bill' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||||
'bill_ends' => ['alias' => false, 'needs_context' => true],
|
'bill_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'bill_starts' => ['alias' => false, 'needs_context' => true],
|
'bill_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'subscription_is' => ['alias' => true, 'alias_for' => 'bill_is', 'needs_context' => true],
|
'subscription_is' => ['alias' => true, 'alias_for' => 'bill_is', 'needs_context' => true],
|
||||||
'subscription_contains' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
'subscription_contains' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||||
'subscription' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
'subscription' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||||
'subscription_ends' => ['alias' => true, 'alias_for' => 'bill_ends', 'needs_context' => true],
|
'subscription_ends' => ['alias' => true, 'alias_for' => 'bill_ends', 'needs_context' => true],
|
||||||
'subscription_starts' => ['alias' => true, 'alias_for' => 'bill_starts', 'needs_context' => true],
|
'subscription_starts' => ['alias' => true, 'alias_for' => 'bill_starts', 'needs_context' => true],
|
||||||
'external_id_is' => ['alias' => false, 'needs_context' => true],
|
'external_id_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_id_contains' => ['alias' => false, 'needs_context' => true],
|
'external_id_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_id' => ['alias' => true, 'alias_for' => 'external_id_contains', 'needs_context' => true],
|
'external_id' => ['alias' => true, 'alias_for' => 'external_id_contains', 'needs_context' => true],
|
||||||
'external_id_ends' => ['alias' => false, 'needs_context' => true],
|
'external_id_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_id_starts' => ['alias' => false, 'needs_context' => true],
|
'external_id_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'internal_reference_is' => ['alias' => false, 'needs_context' => true],
|
'internal_reference_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'internal_reference_contains' => ['alias' => false, 'needs_context' => true],
|
'internal_reference_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'internal_reference' => ['alias' => true, 'alias_for' => 'internal_reference_contains', 'needs_context' => true],
|
'internal_reference' => ['alias' => true, 'alias_for' => 'internal_reference_contains', 'needs_context' => true],
|
||||||
'internal_reference_ends' => ['alias' => false, 'needs_context' => true],
|
'internal_reference_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'internal_reference_starts' => ['alias' => false, 'needs_context' => true],
|
'internal_reference_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_url_is' => ['alias' => false, 'needs_context' => true],
|
'external_url_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_url_contains' => ['alias' => false, 'needs_context' => true],
|
'external_url_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_url' => ['alias' => true, 'alias_for' => 'external_url_contains', 'needs_context' => true],
|
'external_url' => ['alias' => true, 'alias_for' => 'external_url_contains', 'needs_context' => true],
|
||||||
'external_url_ends' => ['alias' => false, 'needs_context' => true],
|
'external_url_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'external_url_starts' => ['alias' => false, 'needs_context' => true],
|
'external_url_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'has_attachments' => ['alias' => false, 'needs_context' => false],
|
'has_attachments' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_any_category' => ['alias' => false, 'needs_context' => false],
|
'has_any_category' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_any_budget' => ['alias' => false, 'needs_context' => false],
|
'has_any_budget' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_any_bill' => ['alias' => false, 'needs_context' => false],
|
'has_any_bill' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_any_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_any_bill'],
|
'has_any_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_any_bill'],
|
||||||
'has_any_tag' => ['alias' => false, 'needs_context' => false],
|
'has_any_tag' => ['alias' => false, 'needs_context' => false],
|
||||||
'any_notes' => ['alias' => false, 'needs_context' => false],
|
'any_notes' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_any_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
'has_any_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
||||||
'has_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
'has_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
||||||
'any_external_url' => ['alias' => false, 'needs_context' => false],
|
'any_external_url' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_any_external_url' => ['alias' => true, 'alias_for' => 'any_external_url', 'needs_context' => false],
|
'has_any_external_url' => ['alias' => true, 'alias_for' => 'any_external_url', 'needs_context' => false],
|
||||||
'has_no_attachments' => ['alias' => false, 'needs_context' => false],
|
'has_no_attachments' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_no_category' => ['alias' => false, 'needs_context' => false],
|
'has_no_category' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_no_budget' => ['alias' => false, 'needs_context' => false],
|
'has_no_budget' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_no_bill' => ['alias' => false, 'needs_context' => false],
|
'has_no_bill' => ['alias' => false, 'needs_context' => false],
|
||||||
'has_no_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_no_bill'],
|
'has_no_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_no_bill'],
|
||||||
'has_no_tag' => ['alias' => false, 'needs_context' => false],
|
'has_no_tag' => ['alias' => false, 'needs_context' => false],
|
||||||
'no_notes' => ['alias' => false, 'needs_context' => false],
|
'no_notes' => ['alias' => false, 'needs_context' => false],
|
||||||
'no_external_url' => ['alias' => false, 'needs_context' => false],
|
'no_external_url' => ['alias' => false, 'needs_context' => false],
|
||||||
'source_is_cash' => ['alias' => false, 'needs_context' => false],
|
'source_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||||
'destination_is_cash' => ['alias' => false, 'needs_context' => false],
|
'destination_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||||
'account_is_cash' => ['alias' => false, 'needs_context' => false],
|
'account_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||||
'currency_is' => ['alias' => false, 'needs_context' => true],
|
'currency_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'foreign_currency_is' => ['alias' => false, 'needs_context' => true],
|
'foreign_currency_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
'id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||||
'journal_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
'journal_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||||
'recurrence_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
'recurrence_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||||
'date_on' => ['alias' => false, 'needs_context' => true],
|
'date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'date' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
'date' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||||
'date_is' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
'date_is' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||||
'on' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
'on' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||||
'date_before' => ['alias' => false, 'needs_context' => true],
|
'date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'before' => ['alias' => true, 'alias_for' => 'date_before', 'needs_context' => true],
|
'before' => ['alias' => true, 'alias_for' => 'date_before', 'needs_context' => true],
|
||||||
'date_after' => ['alias' => false, 'needs_context' => true],
|
'date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'after' => ['alias' => true, 'alias_for' => 'date_after', 'needs_context' => true],
|
'after' => ['alias' => true, 'alias_for' => 'date_after', 'needs_context' => true],
|
||||||
'interest_date_on' => ['alias' => false, 'needs_context' => true],
|
'interest_date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'interest_date' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
'interest_date' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
||||||
'interest_date_is' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
'interest_date_is' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
||||||
'interest_date_before' => ['alias' => false, 'needs_context' => true],
|
'interest_date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'interest_date_after' => ['alias' => false, 'needs_context' => true],
|
'interest_date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'book_date_on' => ['alias' => false, 'needs_context' => true],
|
'book_date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'book_date' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
'book_date' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
||||||
'book_date_is' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
'book_date_is' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
||||||
'book_date_before' => ['alias' => false, 'needs_context' => true],
|
'book_date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'book_date_after' => ['alias' => false, 'needs_context' => true],
|
'book_date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'process_date_on' => ['alias' => false, 'needs_context' => true],
|
'process_date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'process_date' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
'process_date' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
||||||
'process_date_is' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
'process_date_is' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
||||||
'process_date_before' => ['alias' => false, 'needs_context' => true],
|
'process_date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'process_date_after' => ['alias' => false, 'needs_context' => true],
|
'process_date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'due_date_on' => ['alias' => false, 'needs_context' => true],
|
'due_date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'due_date' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
'due_date' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
||||||
'due_date_is' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
'due_date_is' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
||||||
'due_date_before' => ['alias' => false, 'needs_context' => true],
|
'due_date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'due_date_after' => ['alias' => false, 'needs_context' => true],
|
'due_date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'payment_date_on' => ['alias' => false, 'needs_context' => true],
|
'payment_date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'payment_date' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
'payment_date' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
||||||
'payment_date_is' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
'payment_date_is' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
||||||
'payment_date_before' => ['alias' => false, 'needs_context' => true],
|
'payment_date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'payment_date_after' => ['alias' => false, 'needs_context' => true],
|
'payment_date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'invoice_date_on' => ['alias' => false, 'needs_context' => true],
|
'invoice_date_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'invoice_date' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
'invoice_date' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
||||||
'invoice_date_is' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
'invoice_date_is' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
||||||
'invoice_date_before' => ['alias' => false, 'needs_context' => true],
|
'invoice_date_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'invoice_date_after' => ['alias' => false, 'needs_context' => true],
|
'invoice_date_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'created_at_on' => ['alias' => false, 'needs_context' => true],
|
'created_at_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'created_at' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
'created_at' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||||
'created_at_is' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
'created_at_is' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||||
'created_at_before' => ['alias' => false, 'needs_context' => true],
|
'created_at_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'created_at_after' => ['alias' => false, 'needs_context' => true],
|
'created_at_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'updated_at_on' => ['alias' => false, 'needs_context' => true],
|
'updated_at_on' => ['alias' => false, 'needs_context' => true],
|
||||||
'updated_at' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
'updated_at' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||||
'updated_at_is' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
'updated_at_is' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||||
'updated_at_before' => ['alias' => false, 'needs_context' => true],
|
'updated_at_before' => ['alias' => false, 'needs_context' => true],
|
||||||
'updated_at_after' => ['alias' => false, 'needs_context' => true],
|
'updated_at_after' => ['alias' => false, 'needs_context' => true],
|
||||||
'created_on_on' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
'created_on_on' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||||
'created_on' => ['alias' => true, 'alias_for' => 'created_at', 'needs_context' => true],
|
'created_on' => ['alias' => true, 'alias_for' => 'created_at', 'needs_context' => true],
|
||||||
'created_on_before' => ['alias' => true, 'alias_for' => 'created_at_before', 'needs_context' => true],
|
'created_on_before' => ['alias' => true, 'alias_for' => 'created_at_before', 'needs_context' => true],
|
||||||
'created_on_after' => ['alias' => true, 'alias_for' => 'created_at_after', 'needs_context' => true],
|
'created_on_after' => ['alias' => true, 'alias_for' => 'created_at_after', 'needs_context' => true],
|
||||||
'updated_on_on' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
'updated_on_on' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||||
'updated_on' => ['alias' => true, 'alias_for' => 'updated_at', 'needs_context' => true],
|
'updated_on' => ['alias' => true, 'alias_for' => 'updated_at', 'needs_context' => true],
|
||||||
'updated_on_before' => ['alias' => true, 'alias_for' => 'updated_at_before', 'needs_context' => true],
|
'updated_on_before' => ['alias' => true, 'alias_for' => 'updated_at_before', 'needs_context' => true],
|
||||||
'updated_on_after' => ['alias' => true, 'alias_for' => 'updated_at_after', 'needs_context' => true],
|
'updated_on_after' => ['alias' => true, 'alias_for' => 'updated_at_after', 'needs_context' => true],
|
||||||
'amount_is' => ['alias' => false, 'needs_context' => true],
|
'amount_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'amount' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
'amount' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
||||||
'amount_exactly' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
'amount_exactly' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
||||||
'amount_less' => ['alias' => false, 'needs_context' => true],
|
'amount_less' => ['alias' => false, 'needs_context' => true],
|
||||||
'amount_max' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
'amount_max' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
||||||
'less' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
'less' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
||||||
'amount_more' => ['alias' => false, 'needs_context' => true],
|
'amount_more' => ['alias' => false, 'needs_context' => true],
|
||||||
'amount_min' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
'amount_min' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
||||||
'more' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
'more' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
||||||
'foreign_amount_is' => ['alias' => false, 'needs_context' => true],
|
'foreign_amount_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'foreign_amount' => ['alias' => true, 'alias_for' => 'foreign_amount_is', 'needs_context' => true],
|
'foreign_amount' => ['alias' => true, 'alias_for' => 'foreign_amount_is', 'needs_context' => true],
|
||||||
'foreign_amount_less' => ['alias' => false, 'needs_context' => true],
|
'foreign_amount_less' => ['alias' => false, 'needs_context' => true],
|
||||||
'foreign_amount_max' => ['alias' => true, 'alias_for' => 'foreign_amount_less', 'needs_context' => true],
|
'foreign_amount_max' => ['alias' => true, 'alias_for' => 'foreign_amount_less', 'needs_context' => true],
|
||||||
'foreign_amount_more' => ['alias' => false, 'needs_context' => true],
|
'foreign_amount_more' => ['alias' => false, 'needs_context' => true],
|
||||||
'foreign_amount_min' => ['alias' => true, 'alias_for' => 'foreign_amount_more', 'needs_context' => true],
|
'foreign_amount_min' => ['alias' => true, 'alias_for' => 'foreign_amount_more', 'needs_context' => true],
|
||||||
'attachment_name_is' => ['alias' => false, 'needs_context' => true],
|
'attachment_name_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
'attachment' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||||
'attachment_is' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
'attachment_is' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||||
'attachment_name' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
'attachment_name' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||||
'attachment_name_contains' => ['alias' => false, 'needs_context' => true],
|
'attachment_name_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_name_starts' => ['alias' => false, 'needs_context' => true],
|
'attachment_name_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_name_ends' => ['alias' => false, 'needs_context' => true],
|
'attachment_name_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_notes' => ['alias' => true, 'alias_for' => 'attachment_notes_are', 'needs_context' => true],
|
'attachment_notes' => ['alias' => true, 'alias_for' => 'attachment_notes_are', 'needs_context' => true],
|
||||||
'attachment_notes_are' => ['alias' => false, 'needs_context' => true],
|
'attachment_notes_are' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_notes_contains' => ['alias' => false, 'needs_context' => true],
|
'attachment_notes_contains' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_notes_contain' => ['alias' => true, 'alias_for' => 'attachment_notes_contains', 'needs_context' => true],
|
'attachment_notes_contain' => ['alias' => true, 'alias_for' => 'attachment_notes_contains', 'needs_context' => true],
|
||||||
'attachment_notes_starts' => ['alias' => false, 'needs_context' => true],
|
'attachment_notes_starts' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_notes_start' => ['alias' => true, 'alias_for' => 'attachment_notes_starts', 'needs_context' => true],
|
'attachment_notes_start' => ['alias' => true, 'alias_for' => 'attachment_notes_starts', 'needs_context' => true],
|
||||||
'attachment_notes_ends' => ['alias' => false, 'needs_context' => true],
|
'attachment_notes_ends' => ['alias' => false, 'needs_context' => true],
|
||||||
'attachment_notes_end' => ['alias' => true, 'alias_for' => 'attachment_notes_ends', 'needs_context' => true],
|
'attachment_notes_end' => ['alias' => true, 'alias_for' => 'attachment_notes_ends', 'needs_context' => true],
|
||||||
'exists' => ['alias' => false, 'needs_context' => false],
|
'exists' => ['alias' => false, 'needs_context' => false],
|
||||||
'sepa_ct_is' => ['alias' => false, 'needs_context' => true],
|
'sepa_ct_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'no_external_id' => ['alias' => false, 'needs_context' => false],
|
'no_external_id' => ['alias' => false, 'needs_context' => false],
|
||||||
'any_external_id' => ['alias' => false, 'needs_context' => false],
|
'any_external_id' => ['alias' => false, 'needs_context' => false],
|
||||||
|
|
||||||
// based on source or destination balance. Very heavy search.
|
// based on source or destination balance. Very heavy search.
|
||||||
'source_balance_gte' => ['alias' => false, 'needs_context' => true],
|
'source_balance_gte' => ['alias' => false, 'needs_context' => true],
|
||||||
'source_balance_gt' => ['alias' => false, 'needs_context' => true],
|
'source_balance_gt' => ['alias' => false, 'needs_context' => true],
|
||||||
'source_balance_lte' => ['alias' => false, 'needs_context' => true],
|
'source_balance_lte' => ['alias' => false, 'needs_context' => true],
|
||||||
'source_balance_lt' => ['alias' => false, 'needs_context' => true],
|
'source_balance_lt' => ['alias' => false, 'needs_context' => true],
|
||||||
'source_balance_is' => ['alias' => false, 'needs_context' => true],
|
'source_balance_is' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination_balance_gte' => ['alias' => false, 'needs_context' => true],
|
'destination_balance_gte' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination_balance_gt' => ['alias' => false, 'needs_context' => true],
|
'destination_balance_gt' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination_balance_lte' => ['alias' => false, 'needs_context' => true],
|
'destination_balance_lte' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination_balance_lt' => ['alias' => false, 'needs_context' => true],
|
'destination_balance_lt' => ['alias' => false, 'needs_context' => true],
|
||||||
'destination_balance_is' => ['alias' => false, 'needs_context' => true],
|
'destination_balance_is' => ['alias' => false, 'needs_context' => true],
|
||||||
],
|
],
|
||||||
/**
|
/**
|
||||||
* Which query parser to use - 'new' or 'legacy'
|
* Which query parser to use - 'new' or 'legacy'
|
||||||
|
566
package-lock.json
generated
566
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -80,18 +80,18 @@
|
|||||||
"profile_oauth_create_new_client": "Vytvo\u0159it nov\u00e9ho klienta",
|
"profile_oauth_create_new_client": "Vytvo\u0159it nov\u00e9ho klienta",
|
||||||
"profile_oauth_create_client": "Vytvo\u0159it klienta",
|
"profile_oauth_create_client": "Vytvo\u0159it klienta",
|
||||||
"profile_oauth_edit_client": "Upravit klienta",
|
"profile_oauth_edit_client": "Upravit klienta",
|
||||||
"profile_oauth_name_help": "Something your users will recognize and trust.",
|
"profile_oauth_name_help": "N\u011bco \u010demu va\u0161i u\u017eivatel\u00e9 budou d\u016fv\u011b\u0159ovat.",
|
||||||
"profile_oauth_redirect_url": "P\u0159esm\u011brovat URL adresu",
|
"profile_oauth_redirect_url": "P\u0159esm\u011brovat URL adresu",
|
||||||
"profile_oauth_clients_external_auth": "If you're using an external authentication provider like Authelia, OAuth Clients will not work. You can use Personal Access Tokens only.",
|
"profile_oauth_clients_external_auth": "Pokud pro ov\u011b\u0159ov\u00e1n\u00ed pou\u017e\u00edv\u00e1te extern\u00ed slu\u017ebu, nap\u0159\u00edklad Authelia, OAuth klienti nemus\u00ed fungovat spr\u00e1vn\u011b. M\u00edsto toho m\u016f\u017eete pou\u017e\u00edt Personal Access Token.",
|
||||||
"profile_oauth_redirect_url_help": "Your application's authorization callback URL.",
|
"profile_oauth_redirect_url_help": "Callback URL va\u0161\u00ed aplikace.",
|
||||||
"profile_authorized_apps": "Authorized applications",
|
"profile_authorized_apps": "Authorized applications",
|
||||||
"profile_authorized_clients": "Autorizovan\u00ed klienti",
|
"profile_authorized_clients": "Autorizovan\u00ed klienti",
|
||||||
"profile_scopes": "Scopes",
|
"profile_scopes": "Scopes",
|
||||||
"profile_revoke": "Revoke",
|
"profile_revoke": "Revoke",
|
||||||
"profile_personal_access_tokens": "Personal Access Tokens",
|
"profile_personal_access_tokens": "Personal Access Token",
|
||||||
"profile_personal_access_token": "Personal Access Token",
|
"profile_personal_access_token": "Personal Access Token",
|
||||||
"profile_personal_access_token_explanation": "Here is your new personal access token. This is the only time it will be shown so don't lose it! You may now use this token to make API requests.",
|
"profile_personal_access_token_explanation": "Tohle je v\u00e1\u0161 nov\u00fd p\u0159\u00edstupov\u00fd token. Tohle je naposled kdy ho vid\u00edte, tak\u017ee ho neztra\u0165te! M\u016f\u017eete ho pou\u017e\u00edt pro vol\u00e1n\u00ed API.",
|
||||||
"profile_no_personal_access_token": "You have not created any personal access tokens.",
|
"profile_no_personal_access_token": "Je\u0161t\u011b jste nevytvo\u0159ili \u017e\u00e1dn\u00e9 p\u0159\u00edstupov\u00e9 tokeny.",
|
||||||
"profile_create_new_token": "Vytvo\u0159it nov\u00fd token",
|
"profile_create_new_token": "Vytvo\u0159it nov\u00fd token",
|
||||||
"profile_create_token": "Vytvo\u0159it token",
|
"profile_create_token": "Vytvo\u0159it token",
|
||||||
"profile_create": "Vytvo\u0159it",
|
"profile_create": "Vytvo\u0159it",
|
||||||
@@ -100,8 +100,8 @@
|
|||||||
"piggy_bank": "Pokladni\u010dka",
|
"piggy_bank": "Pokladni\u010dka",
|
||||||
"profile_oauth_client_secret_title": "Client Secret",
|
"profile_oauth_client_secret_title": "Client Secret",
|
||||||
"profile_oauth_client_secret_expl": "Here is your new client secret. This is the only time it will be shown so don't lose it! You may now use this secret to make API requests.",
|
"profile_oauth_client_secret_expl": "Here is your new client secret. This is the only time it will be shown so don't lose it! You may now use this secret to make API requests.",
|
||||||
"profile_oauth_confidential": "Confidential",
|
"profile_oauth_confidential": "Soukrom\u00e1 aplikace",
|
||||||
"profile_oauth_confidential_help": "Require the client to authenticate with a secret. Confidential clients can hold credentials in a secure way without exposing them to unauthorized parties. Public applications, such as native desktop or JavaScript SPA applications, are unable to hold secrets securely.",
|
"profile_oauth_confidential_help": "Po\u017eadovat aby se klienti autorizovali. Soukrom\u00e9 aplikace mohou bezpe\u010dn\u011b pracovat s p\u0159\u00edstupov\u00fdmi \u00fadaji bez toho aby je zve\u0159ejnily. Ve\u0159ejn\u00e9 aplikace, nativn\u00ed nebo JavaScriptov\u00e9 SPA, toho schopn\u00e9 nejsou.",
|
||||||
"multi_account_warning_unknown": "Depending on the type of transaction you create, the source and\/or destination account of subsequent splits may be overruled by whatever is defined in the first split of the transaction.",
|
"multi_account_warning_unknown": "Depending on the type of transaction you create, the source and\/or destination account of subsequent splits may be overruled by whatever is defined in the first split of the transaction.",
|
||||||
"multi_account_warning_withdrawal": "Zdrojov\u00fd \u00fa\u010del v\u0161ech n\u00e1sleduj\u00edc\u00edch rozd\u011blen\u00ed je ovl\u00e1dan\u00fd zdrojov\u00fdm \u00fa\u010dtem prvn\u00edho rozd\u011blen\u00ed transakce.",
|
"multi_account_warning_withdrawal": "Zdrojov\u00fd \u00fa\u010del v\u0161ech n\u00e1sleduj\u00edc\u00edch rozd\u011blen\u00ed je ovl\u00e1dan\u00fd zdrojov\u00fdm \u00fa\u010dtem prvn\u00edho rozd\u011blen\u00ed transakce.",
|
||||||
"multi_account_warning_deposit": "C\u00edlov\u00fd \u00fa\u010del v\u0161ech n\u00e1sleduj\u00edc\u00edch rozd\u011blen\u00ed je ovl\u00e1dan\u00fd c\u00edlov\u00fdm \u00fa\u010dtem prvn\u00edho rozd\u011blen\u00ed transakce.",
|
"multi_account_warning_deposit": "C\u00edlov\u00fd \u00fa\u010del v\u0161ech n\u00e1sleduj\u00edc\u00edch rozd\u011blen\u00ed je ovl\u00e1dan\u00fd c\u00edlov\u00fdm \u00fa\u010dtem prvn\u00edho rozd\u011blen\u00ed transakce.",
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
"attempt_content_title": "Pokusy webhooku",
|
"attempt_content_title": "Pokusy webhooku",
|
||||||
"attempt_content_help": "To v\u0161e jsou ne\u00fasp\u011b\u0161n\u00e9 pokusy t\u00e9to zpravy webhooku o odesl\u00e1n\u00ed na nakonfigurovanou URL. Po n\u011bjak\u00e9 dob\u011b, Firefly III p\u0159estane zkou\u0161et odes\u00edlat zpr\u00e1vu.",
|
"attempt_content_help": "To v\u0161e jsou ne\u00fasp\u011b\u0161n\u00e9 pokusy t\u00e9to zpravy webhooku o odesl\u00e1n\u00ed na nakonfigurovanou URL. Po n\u011bjak\u00e9 dob\u011b, Firefly III p\u0159estane zkou\u0161et odes\u00edlat zpr\u00e1vu.",
|
||||||
"no_attempts": "Nebyly nalezeny \u017e\u00e1dn\u00e9 ne\u00fasp\u011b\u0161n\u00e9 pokusy. To je dobr\u00e1 v\u011bc!",
|
"no_attempts": "Nebyly nalezeny \u017e\u00e1dn\u00e9 ne\u00fasp\u011b\u0161n\u00e9 pokusy. To je dobr\u00e1 v\u011bc!",
|
||||||
"webhook_attempt_at": "Attempt at {moment}",
|
"webhook_attempt_at": "Pokus v {moment}",
|
||||||
"logs": "Logy",
|
"logs": "Logy",
|
||||||
"response": "Odpov\u011b\u010f",
|
"response": "Odpov\u011b\u010f",
|
||||||
"visit_webhook_url": "Nav\u0161t\u00edvit URL webhooku",
|
"visit_webhook_url": "Nav\u0161t\u00edvit URL webhooku",
|
||||||
|
@@ -153,7 +153,7 @@
|
|||||||
"url": "URL",
|
"url": "URL",
|
||||||
"active": "Activo",
|
"active": "Activo",
|
||||||
"interest_date": "Fecha de inter\u00e9s",
|
"interest_date": "Fecha de inter\u00e9s",
|
||||||
"administration_currency": "Native currency",
|
"administration_currency": "Moneda nativa",
|
||||||
"title": "T\u00edtulo",
|
"title": "T\u00edtulo",
|
||||||
"date": "Fecha",
|
"date": "Fecha",
|
||||||
"book_date": "Fecha de registro",
|
"book_date": "Fecha de registro",
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
"is_reconciled": "\u5df2\u6838\u9500",
|
"is_reconciled": "\u5df2\u6838\u9500",
|
||||||
"split": "\u62c6\u5206",
|
"split": "\u62c6\u5206",
|
||||||
"single_split": "\u62c6\u5206",
|
"single_split": "\u62c6\u5206",
|
||||||
"not_enough_currencies": "Not enough currencies",
|
"not_enough_currencies": "\u6ca1\u6709\u8db3\u591f\u7684\u8d27\u5e01",
|
||||||
"not_enough_currencies_enabled": "\u5982\u679c\u60a8\u53ea\u542f\u7528\u4e86\u4e00\u79cd\u8d27\u5e01\uff0c\u5c31\u4e0d\u9700\u8981\u6dfb\u52a0\u6c47\u7387\u3002",
|
"not_enough_currencies_enabled": "\u5982\u679c\u60a8\u53ea\u542f\u7528\u4e86\u4e00\u79cd\u8d27\u5e01\uff0c\u5c31\u4e0d\u9700\u8981\u6dfb\u52a0\u6c47\u7387\u3002",
|
||||||
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u4ea4\u6613 #{ID} (\u201c{title}\u201d)<\/a> \u5df2\u4fdd\u5b58\u3002",
|
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u4ea4\u6613 #{ID} (\u201c{title}\u201d)<\/a> \u5df2\u4fdd\u5b58\u3002",
|
||||||
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\u63a8\u9001 #{ID} (\"{title}\")<\/a> \u5df2\u4fdd\u5b58.",
|
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\u63a8\u9001 #{ID} (\"{title}\")<\/a> \u5df2\u4fdd\u5b58.",
|
||||||
@@ -153,7 +153,7 @@
|
|||||||
"url": "\u7f51\u5740",
|
"url": "\u7f51\u5740",
|
||||||
"active": "\u542f\u7528",
|
"active": "\u542f\u7528",
|
||||||
"interest_date": "\u5229\u606f\u65e5\u671f",
|
"interest_date": "\u5229\u606f\u65e5\u671f",
|
||||||
"administration_currency": "Native currency",
|
"administration_currency": "\u672c\u5730\u8d27\u5e01",
|
||||||
"title": "\u6807\u9898",
|
"title": "\u6807\u9898",
|
||||||
"date": "\u65e5\u671f",
|
"date": "\u65e5\u671f",
|
||||||
"book_date": "\u767b\u8bb0\u65e5\u671f",
|
"book_date": "\u767b\u8bb0\u65e5\u671f",
|
||||||
@@ -166,14 +166,14 @@
|
|||||||
"webhook_response": "\u54cd\u5e94\u5185\u5bb9",
|
"webhook_response": "\u54cd\u5e94\u5185\u5bb9",
|
||||||
"webhook_trigger": "\u89e6\u53d1\u6761\u4ef6",
|
"webhook_trigger": "\u89e6\u53d1\u6761\u4ef6",
|
||||||
"webhook_delivery": "\u53d1\u9001\u683c\u5f0f",
|
"webhook_delivery": "\u53d1\u9001\u683c\u5f0f",
|
||||||
"from_currency_to_currency": "{from} → {to}",
|
"from_currency_to_currency": "{from}→{to}",
|
||||||
"to_currency_from_currency": "{to} → {from}",
|
"to_currency_from_currency": "{to}→{from}",
|
||||||
"rate": "Rate"
|
"rate": "\u8bc4\u7ea7"
|
||||||
},
|
},
|
||||||
"list": {
|
"list": {
|
||||||
"title": "\u6807\u9898",
|
"title": "\u6807\u9898",
|
||||||
"active": "\u662f\u5426\u542f\u7528\uff1f",
|
"active": "\u662f\u5426\u542f\u7528\uff1f",
|
||||||
"native_currency": "Native currency",
|
"native_currency": "\u672c\u5730\u8d27\u5e01",
|
||||||
"trigger": "\u89e6\u53d1\u6761\u4ef6",
|
"trigger": "\u89e6\u53d1\u6761\u4ef6",
|
||||||
"response": "\u7b54\u590d",
|
"response": "\u7b54\u590d",
|
||||||
"delivery": "\u4ea4\u4ed8",
|
"delivery": "\u4ea4\u4ed8",
|
||||||
|
Reference in New Issue
Block a user