Compare commits

..

31 Commits

Author SHA1 Message Date
github-actions[bot]
5b0be91f93 Merge pull request #10885 from firefly-iii/release-1757479782
🤖 Automatically merge the PR into the develop branch.
2025-09-10 06:49:50 +02:00
JC5
01e7b604da 🤖 Auto commit for release 'develop' on 2025-09-10 2025-09-10 06:49:42 +02:00
James Cole
58d175444b Fix #10883 2025-09-10 06:43:24 +02:00
James Cole
134770644a Fix amounts in transaction. 2025-09-09 17:14:53 +02:00
James Cole
a9f21c9371 Extra text in the PR. 2025-09-09 15:53:25 +02:00
github-actions[bot]
781947beeb Merge pull request #10879 from firefly-iii/release-1757425805
🤖 Automatically merge the PR into the develop branch.
2025-09-09 15:50:18 +02:00
JC5
9760cd2f97 🤖 Auto commit for release 'develop' on 2025-09-09 2025-09-09 15:50:06 +02:00
James Cole
d317e9ec32 Update changelog. 2025-09-09 15:41:19 +02:00
James Cole
534f7fcadb Merge branch 'main' into develop 2025-09-09 15:36:55 +02:00
James Cole
fb3f7a1d4b Merge pull request #10874 from firefly-iii/dependabot/github_actions/actions/stale-10
Bump actions/stale from 9 to 10
2025-09-08 11:41:37 +02:00
James Cole
bf2c3e3561 Merge pull request #10873 from firefly-iii/dependabot/github_actions/actions/github-script-8
Bump actions/github-script from 7 to 8
2025-09-08 11:41:12 +02:00
github-actions[bot]
b670f81dcd Merge pull request #10875 from firefly-iii/release-1757313349
🤖 Automatically merge the PR into the develop branch.
2025-09-08 08:36:01 +02:00
JC5
7aac1cdf67 🤖 Auto commit for release 'develop' on 2025-09-08 2025-09-08 08:35:49 +02:00
Sander Dorigo
fa0ac8a16c Fix php files 2025-09-08 08:31:09 +02:00
dependabot[bot]
0990b1f0b4 Bump actions/stale from 9 to 10
Bumps [actions/stale](https://github.com/actions/stale) from 9 to 10.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v9...v10)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 03:08:14 +00:00
dependabot[bot]
c1922670c8 Bump actions/github-script from 7 to 8
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 03:08:10 +00:00
James Cole
81cd89d66f Final nestor and phpstan fixes. 2025-09-07 17:42:16 +02:00
James Cole
f5c202543c Clean up code. 2025-09-07 17:31:08 +02:00
James Cole
034f437c6b Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-09-07 17:30:43 +02:00
James Cole
8550ba6138 Remove unused code. 2025-09-07 17:30:34 +02:00
github-actions[bot]
a51501025b Merge pull request #10872 from firefly-iii/release-1757249926
🤖 Automatically merge the PR into the develop branch.
2025-09-07 14:58:53 +02:00
JC5
a9d26e4586 🤖 Auto commit for release 'develop' on 2025-09-07 2025-09-07 14:58:46 +02:00
James Cole
949691935f Catch exceptions. 2025-09-07 14:54:44 +02:00
James Cole
4835b05304 Optimize currency search. 2025-09-07 14:49:49 +02:00
James Cole
cce5a73dd2 Clean up and fix phpstan issues. 2025-09-07 14:28:58 +02:00
github-actions[bot]
3152f635dd Merge pull request #10868 from firefly-iii/release-1757235851
🤖 Automatically merge the PR into the develop branch.
2025-09-07 11:04:21 +02:00
JC5
12e8651017 🤖 Auto commit for release 'develop' on 2025-09-07 2025-09-07 11:04:11 +02:00
James Cole
f88286c848 Merge branches 'develop' and 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-09-07 10:59:12 +02:00
James Cole
39cf0533d9 Fix various phpstan issues. 2025-09-07 10:59:07 +02:00
James Cole
75dfdcc220 Fix final phpstan issue. 2025-09-07 07:51:35 +02:00
James Cole
c3a3bdf525 Fix phpstan issues. 2025-09-07 07:51:01 +02:00
131 changed files with 558 additions and 2965 deletions

View File

@@ -7,28 +7,24 @@ parameters:
- ../bootstrap/app.php
universalObjectCratesClasses:
- Illuminate\Database\Eloquent\Model
# TODO: slowly remove these parameters and fix the issues found.
reportUnmatchedIgnoredErrors: true
ignoreErrors:
# TODO: slowly remove these exceptions and fix the issues found.
- '#Dynamic call to static method#' # all the Laravel ORM things depend on this.
- identifier: varTag.nativeType
- identifier: varTag.type
# all errors below I will never fix.
- '#expects view-string\|null, string given#'
- '#expects view-string, string given#'
- "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
- identifier: missingType.generics # not interesting enough to fix.
-
identifier: larastan.noEnvCallsOutsideOfConfig
path: ../app/Console/Commands/System/CreatesDatabase.php
- identifier: missingType.iterableValue # not interesting enough to fix.
- identifier: missingType.generics # not interesting enough to fix.
- "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
- '#expects view-string, string given#'
- '#expects view-string\|null, string given#'
# phpstan can't handle this so we ignore them.
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::before#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::after#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::withTrashed#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::accountTypeIn#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\BelongsTo::withTrashed#'
- identifier: varTag.type # needs a custom extension for every repository, not gonna happen.
- '#Dynamic call to static method Illuminate#'
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::before#' # is custom scope
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::after#' # is custom scope
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::withTrashed#' # is to allow soft delete
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::accountTypeIn#' # is a custom scope
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\BelongsTo::withTrashed#' # is to allow soft delete
# The level 8 is the highest level. original was 5
# 7 is more than enough, higher just leaves NULL things.

View File

@@ -15,7 +15,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Prune cancelled/skipped runs
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -45,7 +45,7 @@ jobs:
}
- name: Prune runs older than 3 days
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |

View File

@@ -250,7 +250,7 @@ jobs:
fi
echo "Merge all changes from $BRANCH_NAME back into '$MERGE_INTO' using a PR"
PR_URL=$(gh pr create -B $MERGE_INTO -H $BRANCH_NAME --title "🤖 Automatic PR to merge all changes into the '$MERGE_INTO' branch." --body '🤖 Created by GitHub action')
PR_URL=$(gh pr create -B $MERGE_INTO -H $BRANCH_NAME --title "🤖 Automatic PR to merge all changes into the '$MERGE_INTO' branch." --body '🤖 This PR was created automatically by a GitHub action to merge the changed files into this branch. It will be merged automatically. `Share and enjoy`')
echo "PR URL is '$PR_URL'"
IFS='/' read -ra parts <<< "$PR_URL"
PR_NR=$(printf %s\\n "${parts[@]:(-1)}")
@@ -272,7 +272,7 @@ jobs:
echo "Also merge everything into main since this is a release."
echo 'create PR'
PR_URL=$(gh pr create -B main -H develop --title "🤖 Automatic PR to merge all changes into the main branch." --body "🤖 Created by GitHub action")
PR_URL=$(gh pr create -B main -H develop --title "🤖 Automatic PR to merge all changes into the main branch." --body "🤖 This PR was created automatically by a GitHub action to merge the changed files into this branch. It will be merged automatically. `Share and enjoy`")
echo "PR URL is '$PR_URL'"
IFS='/' read -ra parts <<< "$PR_URL"

View File

@@ -15,7 +15,7 @@ jobs:
actions: write
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: |

View File

@@ -31,10 +31,10 @@ use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
@@ -133,9 +133,9 @@ class BudgetController extends Controller
$row['pc_left'] = '0';
$row['pc_overspent'] = '0';
if (null !== $limit) {
if ($limit instanceof BudgetLimit) {
$row['budgeted'] = $limit->amount;
$row['left'] = bcsub($row['budgeted'], bcmul($row['spent'], '-1'));
$row['left'] = bcsub((string) $row['budgeted'], bcmul((string) $row['spent'], '-1'));
$row['overspent'] = bcmul($row['left'], '-1');
$row['left'] = 1 === bccomp($row['left'], '0') ? $row['left'] : '0';
$row['overspent'] = 1 === bccomp($row['overspent'], '0') ? $row['overspent'] : '0';
@@ -143,7 +143,7 @@ class BudgetController extends Controller
// convert data if necessary.
if (true === $this->convertToPrimary && $currencyId !== $this->primaryCurrency->id) {
$currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$currencies[$currencyId] ??= Amount::getTransactionCurrencyById($currencyId);
$row['pc_budgeted'] = $converter->convert($currencies[$currencyId], $this->primaryCurrency, $start, $row['budgeted']);
$row['pc_spent'] = $converter->convert($currencies[$currencyId], $this->primaryCurrency, $start, $row['spent']);
$row['pc_left'] = $converter->convert($currencies[$currencyId], $this->primaryCurrency, $start, $row['left']);
@@ -231,7 +231,7 @@ class BudgetController extends Controller
* @var array $block
*/
foreach ($spent as $currencyId => $block) {
$this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] ??= Amount::getTransactionCurrencyById($currencyId);
$return[$currencyId] ??= [
'currency_id' => (string)$currencyId,
'currency_code' => $block['currency_code'],
@@ -250,7 +250,9 @@ class BudgetController extends Controller
// var_dump($return);
/** @var array $journal */
foreach ($currentBudgetArray['transaction_journals'] as $journal) {
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string)$journal['amount']);
/** @var numeric-string $amount */
$amount = (string)$journal['amount'];
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $amount);
}
}

View File

@@ -27,7 +27,6 @@ namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Exceptions\BadHttpHeaderException;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
@@ -157,7 +156,6 @@ abstract class Controller extends BaseController
/** @var User $user */
$user = auth()->user();
/** @var Preference $pageSize */
$pageSize = (int)app('preferences')->getForUser($user, 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}

View File

@@ -33,6 +33,7 @@ use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\ExchangeRateTransformer;
use Illuminate\Http\JsonResponse;
@@ -69,7 +70,7 @@ class StoreController extends Controller
foreach ($data as $date => $rate) {
$date = Carbon::createFromFormat('Y-m-d', $date);
$existing = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null !== $existing) {
if ($existing instanceof CurrencyExchangeRate) {
// update existing rate.
$existing = $this->repository->updateExchangeRate($existing, $rate);
$collection->push($existing);
@@ -98,12 +99,9 @@ class StoreController extends Controller
$from = $request->getFromCurrency();
$collection = new Collection();
foreach ($data['rates'] as $key => $rate) {
$to = TransactionCurrency::where('code', $key)->first();
if (null === $to) {
continue; // should not happen.
}
$to = Amount::getTransactionCurrencyByCode($key);
$existing = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null !== $existing) {
if ($existing instanceof CurrencyExchangeRate) {
// update existing rate.
$existing = $this->repository->updateExchangeRate($existing, $rate);
$collection->push($existing);

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\Account;
use Illuminate\Validation\Validator;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Rules\IsValidSortInstruction;
@@ -30,7 +31,6 @@ use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User;
use Illuminate\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class ShowRequest extends FormRequest

View File

@@ -24,10 +24,12 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
use Illuminate\Validation\Validator;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class StoreByDateRequest extends FormRequest
@@ -35,6 +37,9 @@ class StoreByDateRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
/**
* @return array<string, mixed>
*/
public function getAll(): array
{
return [
@@ -45,11 +50,13 @@ class StoreByDateRequest extends FormRequest
public function getFromCurrency(): TransactionCurrency
{
return TransactionCurrency::where('code', $this->get('from'))->first();
return Amount::getTransactionCurrencyByCode((string)$this->get('from'));
}
/**
* The rules that the incoming request must be matched against.
*
* @return array<string, string>
*/
public function rules(): array
{
@@ -79,8 +86,10 @@ class StoreByDateRequest extends FormRequest
continue;
}
$to = TransactionCurrency::where('code', $key)->first();
if (null === $to) {
try {
$to = Amount::getTransactionCurrencyByCode((string)$key);
} catch (FireflyException) {
$validator->errors()->add(sprintf('rates.%s', $key), trans('validation.invalid_currency_code', ['code' => $key]));
}
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
use Carbon\Carbon;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -42,7 +43,7 @@ class StoreRequest extends FormRequest
public function getFromCurrency(): TransactionCurrency
{
return TransactionCurrency::where('code', $this->get('from'))->first();
return Amount::getTransactionCurrencyByCode((string) $this->get('from'));
}
public function getRate(): string
@@ -52,7 +53,7 @@ class StoreRequest extends FormRequest
public function getToCurrency(): TransactionCurrency
{
return TransactionCurrency::where('code', $this->get('to'))->first();
return Amount::getTransactionCurrencyByCode((string) $this->get('to'));
}
/**

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\PiggyBank;
use Illuminate\Validation\Validator;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
@@ -96,7 +97,7 @@ class StoreRequest extends FormRequest
// validate start before end only if both are there.
$data = $validator->getData();
$currency = $this->getCurrencyFromData($validator, $data);
if (null === $currency) {
if (!$currency instanceof TransactionCurrency) {
return;
}
$targetAmount = (string) ($data['target_amount'] ?? '0');
@@ -135,16 +136,10 @@ class StoreRequest extends FormRequest
private function getCurrencyFromData(Validator $validator, array $data): ?TransactionCurrency
{
if (array_key_exists('transaction_currency_code', $data) && '' !== (string) $data['transaction_currency_code']) {
$currency = TransactionCurrency::whereCode($data['transaction_currency_code'])->first();
if (null !== $currency) {
return $currency;
}
return Amount::getTransactionCurrencyByCode((string) $data['transaction_currency_code']);
}
if (array_key_exists('transaction_currency_id', $data) && '' !== (string) $data['transaction_currency_id']) {
$currency = TransactionCurrency::find((int) $data['transaction_currency_id']);
if (null !== $currency) {
return $currency;
}
return Amount::getTransactionCurrencyById((int) $data['transaction_currency_id']);
}
$validator->errors()->add('transaction_currency_id', trans('validation.require_currency_id_code'));

View File

@@ -66,7 +66,7 @@ class RemovesDatabaseDecryption extends Command
* @var string $table
* @var array $fields
*/
foreach ($tables as $table => $fields) {
foreach ($tables as $table => $fields) { // @phpstan-ignore-line
$this->decryptTable($table, $fields);
}

View File

@@ -25,9 +25,11 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Upgrade;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
@@ -65,7 +67,7 @@ class UpgradesCurrencyPreferences extends Command
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool) $configVar->data;
return (bool)$configVar->data;
}
return false;
@@ -104,8 +106,8 @@ class UpgradesCurrencyPreferences extends Command
private function upgradeUserPreferences(User $user): void
{
$currencies = TransactionCurrency::get();
$enabled = new Collection();
$currencies = TransactionCurrency::get();
$enabled = new Collection();
/** @var TransactionCurrency $currency */
foreach ($currencies as $currency) {
@@ -116,10 +118,11 @@ class UpgradesCurrencyPreferences extends Command
$user->currencies()->sync($enabled->pluck('id')->toArray());
// set the default currency for the user and for the group:
$preference = $this->getPreference($user);
$primaryCurrency = TransactionCurrency::where('code', $preference)->first();
if (null === $primaryCurrency) {
// get EUR
$preference = $this->getPreference($user);
try {
$primaryCurrency = Amount::getTransactionCurrencyByCode($preference);
} catch (FireflyException) {
$primaryCurrency = TransactionCurrency::where('code', 'EUR')->first();
}
$user->currencies()->updateExistingPivot($primaryCurrency->id, ['user_default' => true]);
@@ -135,7 +138,7 @@ class UpgradesCurrencyPreferences extends Command
}
if (null !== $preference->data && !is_array($preference->data)) {
return (string) $preference->data;
return (string)$preference->data;
}
return 'EUR';

View File

@@ -170,7 +170,7 @@ class GracefulNotFoundHandler extends ExceptionHandler
}
/** @var null|Account $account */
$account = $user->accounts()->with(['accountType'])->withTrashed()->find($accountId);
$account = $user->accounts()->withTrashed()->with(['accountType'])->find($accountId);
if (null === $account) {
app('log')->error(sprintf('Could not find account %d, so give big fat error.', $accountId));

View File

@@ -26,7 +26,9 @@ namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log;
/**
* Class TransactionCurrencyFactory
@@ -41,14 +43,14 @@ class TransactionCurrencyFactory
$data['code'] = e($data['code']);
$data['symbol'] = e($data['symbol']);
$data['name'] = e($data['name']);
$data['decimal_places'] = (int) $data['decimal_places'];
$data['decimal_places'] = (int)$data['decimal_places'];
// if the code already exists (deleted)
// force delete it and then create the transaction:
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
if (1 === $count) {
$old = TransactionCurrency::withTrashed()->whereCode($data['code'])->first();
$old->forceDelete();
app('log')->warning(sprintf('Force deleted old currency with ID #%d and code "%s".', $old->id, $data['code']));
Log::warning(sprintf('Force deleted old currency with ID #%d and code "%s".', $old->id, $data['code']));
}
try {
@@ -64,8 +66,8 @@ class TransactionCurrencyFactory
);
} catch (QueryException $e) {
$result = null;
app('log')->error(sprintf('Could not create new currency: %s', $e->getMessage()));
app('log')->error($e->getTraceAsString());
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
throw new FireflyException('400004: Could not store new currency.', 0, $e);
}
@@ -76,32 +78,33 @@ class TransactionCurrencyFactory
public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{
$currencyCode = e($currencyCode);
$currencyId = (int) $currencyId;
$currencyId = (int)$currencyId;
$currency = null;
if ('' === $currencyCode && 0 === $currencyId) {
app('log')->debug('Cannot find anything on empty currency code and empty currency ID!');
Log::debug('Cannot find anything on empty currency code and empty currency ID!');
return null;
}
// first by ID:
if ($currencyId > 0) {
$currency = TransactionCurrency::find($currencyId);
if (null !== $currency) {
return $currency;
try {
$currency = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {
Log::warning(sprintf('Currency ID is #%d but found nothing!', $currencyId));
}
app('log')->warning(sprintf('Currency ID is %d but found nothing!', $currencyId));
}
// then by code:
if ('' !== $currencyCode) {
$currency = TransactionCurrency::whereCode($currencyCode)->first();
if (null !== $currency) {
return $currency;
if ('' !== $currencyCode && null === $currency) {
try {
$currency = Amount::getTransactionCurrencyByCode($currencyCode);
} catch (FireflyException) {
Log::warning(sprintf('Currency code is "%s" but found nothing!', $currencyCode));
}
app('log')->warning(sprintf('Currency code is %d but found nothing!', $currencyCode));
}
app('log')->warning('Found nothing for currency.');
Log::info(sprintf('Found currency #%d based on ID %d and code "%s".', $currency->id, $currencyId, $currencyCode));
return null;
return $currency;
}
}

View File

@@ -32,7 +32,6 @@ use FireflyIII\Notifications\Admin\UserInvitation;
use FireflyIII\Notifications\Admin\VersionCheckResult;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\Test\OwnerTestNotificationEmail;
use FireflyIII\Notifications\Test\OwnerTestNotificationNtfy;
use FireflyIII\Notifications\Test\OwnerTestNotificationPushover;
use FireflyIII\Notifications\Test\OwnerTestNotificationSlack;
use Illuminate\Support\Facades\Log;

View File

@@ -44,7 +44,6 @@ use FireflyIII\Models\UserRole;
use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification;
use FireflyIII\Notifications\Security\UserFailedLoginAttempt;
use FireflyIII\Notifications\Test\UserTestNotificationEmail;
use FireflyIII\Notifications\Test\UserTestNotificationNtfy;
use FireflyIII\Notifications\Test\UserTestNotificationPushover;
use FireflyIII\Notifications\Test\UserTestNotificationSlack;
use FireflyIII\Notifications\User\UserLogin;
@@ -129,7 +128,7 @@ class UserEventHandler
$groupTitle = $user->email;
$index = 1;
/** @var UserGroup $group */
/** @var null|UserGroup $group */
$group = null;
// create a new group.

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Collector\Extensions;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
@@ -919,6 +920,8 @@ trait MetaCollection
{
$this->withCategoryInformation();
$this->query->whereNull('category_transaction_journal.category_id');
// better fix for #10507
$this->query->whereNotIn('transaction_types.type', [TransactionTypeEnum::OPENING_BALANCE->value]);
return $this;
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use Closure;
use Exception;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
@@ -45,7 +46,6 @@ use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Closure;
use Override;
use function Safe\json_decode;
@@ -303,7 +303,7 @@ class GroupCollector implements GroupCollectorInterface
foreach ($params as $param) {
$replace = sprintf('"%s"', $param);
if (is_int($param)) {
$replace = (string) $param;
$replace = (string)$param;
}
$pos = strpos($query, '?');
if (false !== $pos) {
@@ -518,13 +518,13 @@ class GroupCollector implements GroupCollectorInterface
/** @var TransactionJournal $augumentedJournal */
foreach ($collection as $augumentedJournal) {
$groupId = (int) $augumentedJournal->transaction_group_id;
$groupId = (int)$augumentedJournal->transaction_group_id;
if (!array_key_exists($groupId, $groups)) {
// make new array
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
$groupArray = [
'id' => (int) $augumentedJournal->transaction_group_id,
'id' => (int)$augumentedJournal->transaction_group_id,
'user_id' => $augumentedJournal->user_id,
'user_group_id' => $augumentedJournal->user_group_id,
// Field transaction_group_title was added by the query.
@@ -537,7 +537,7 @@ class GroupCollector implements GroupCollectorInterface
'transactions' => [],
];
// Field transaction_journal_id was added by the query.
$journalId = (int) $augumentedJournal->transaction_journal_id;
$journalId = (int)$augumentedJournal->transaction_journal_id;
$groupArray['transactions'][$journalId] = $parsedGroup;
$groups[$groupId] = $groupArray;
@@ -545,7 +545,7 @@ class GroupCollector implements GroupCollectorInterface
}
// or parse the rest.
// Field transaction_journal_id was added by the query.
$journalId = (int) $augumentedJournal->transaction_journal_id;
$journalId = (int)$augumentedJournal->transaction_journal_id;
if (array_key_exists($journalId, $groups[$groupId]['transactions'])) {
// append data to existing group + journal (for multiple tags or multiple attachments)
$groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
@@ -597,8 +597,8 @@ class GroupCollector implements GroupCollectorInterface
$dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date'];
if (array_key_exists('meta_name', $result) && in_array($result['meta_name'], $dates, true)) {
$name = $result['meta_name'];
if (array_key_exists('meta_data', $result) && '' !== (string) $result['meta_data']) {
$result[$name] = Carbon::createFromFormat('!Y-m-d', substr((string) json_decode((string) $result['meta_data']), 0, 10));
if (array_key_exists('meta_data', $result) && '' !== (string)$result['meta_data']) {
$result[$name] = Carbon::createFromFormat('!Y-m-d', substr((string)json_decode((string)$result['meta_data']), 0, 10));
}
}
@@ -611,9 +611,9 @@ class GroupCollector implements GroupCollectorInterface
// convert back to strings because SQLite is dumb like that.
$result = $this->convertToStrings($result);
$result['reconciled'] = 1 === (int) $result['reconciled'];
$result['reconciled'] = 1 === (int)$result['reconciled'];
if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well.
$tagId = (int) $augumentedJournal['tag_id'];
$tagId = (int)$augumentedJournal['tag_id'];
$tagDate = null;
try {
@@ -623,7 +623,7 @@ class GroupCollector implements GroupCollectorInterface
}
$result['tags'][$tagId] = [
'id' => (int) $result['tag_id'],
'id' => (int)$result['tag_id'],
'name' => $result['tag_name'],
'date' => $tagDate,
'description' => $result['tag_description'],
@@ -632,8 +632,8 @@ class GroupCollector implements GroupCollectorInterface
// also merge attachments:
if (array_key_exists('attachment_id', $result)) {
$uploaded = 1 === (int) $result['attachment_uploaded'];
$attachmentId = (int) $augumentedJournal['attachment_id'];
$uploaded = 1 === (int)$result['attachment_uploaded'];
$attachmentId = (int)$augumentedJournal['attachment_id'];
if (0 !== $attachmentId && $uploaded) {
$result['attachments'][$attachmentId] = [
'id' => $attachmentId,
@@ -659,7 +659,7 @@ class GroupCollector implements GroupCollectorInterface
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int) $array[$field] : null;
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
}
return $array;
@@ -668,7 +668,7 @@ class GroupCollector implements GroupCollectorInterface
private function convertToBoolean(array $array): array
{
foreach ($this->booleanFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (bool) $array[$field] : null;
$array[$field] = array_key_exists($field, $array) ? (bool)$array[$field] : null;
}
return $array;
@@ -677,7 +677,7 @@ class GroupCollector implements GroupCollectorInterface
private function convertToStrings(array $array): array
{
foreach ($this->stringFields as $field) {
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string) $array[$field] : null;
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string)$array[$field] : null;
}
return $array;
@@ -687,7 +687,7 @@ class GroupCollector implements GroupCollectorInterface
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int) $newJournal['tag_id'];
$tagId = (int)$newJournal['tag_id'];
$tagDate = null;
@@ -698,7 +698,7 @@ class GroupCollector implements GroupCollectorInterface
}
$existingJournal['tags'][$tagId] = [
'id' => (int) $newArray['tag_id'],
'id' => (int)$newArray['tag_id'],
'name' => $newArray['tag_name'],
'date' => $tagDate,
'description' => $newArray['tag_description'],
@@ -712,7 +712,7 @@ class GroupCollector implements GroupCollectorInterface
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int) $newJournal['attachment_id'];
$attachmentId = (int)$newJournal['attachment_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
@@ -731,13 +731,13 @@ class GroupCollector implements GroupCollectorInterface
foreach ($groups as $groudId => $group) {
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
$currencyId = (int) $transaction['currency_id'];
$currencyId = (int)$transaction['currency_id'];
if (null === $transaction['amount']) {
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
}
$pcAmount = (string) ('' === $transaction['pc_amount'] ? '0' : $transaction['pc_amount']);
$pcForeignAmount = (string) ('' === $transaction['pc_foreign_amount'] ? '0' : $transaction['pc_foreign_amount']);
$foreignAmount = (string) ('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
$pcAmount = (string)('' === $transaction['pc_amount'] ? '0' : $transaction['pc_amount']);
$pcForeignAmount = (string)('' === $transaction['pc_foreign_amount'] ? '0' : $transaction['pc_foreign_amount']);
$foreignAmount = (string)('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
@@ -748,11 +748,11 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string) $groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd((string) $groups[$groudId]['sums'][$currencyId]['pc_amount'], $pcAmount);
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['pc_amount'], $pcAmount);
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int) $transaction['foreign_currency_id'];
$currencyId = (int)$transaction['foreign_currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
@@ -763,7 +763,7 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string) $groups[$groudId]['sums'][$currencyId]['amount'], $foreignAmount);
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['amount'], $foreignAmount);
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $pcForeignAmount);
}
}
@@ -1095,10 +1095,6 @@ class GroupCollector implements GroupCollectorInterface
->whereNull('transaction_groups.deleted_at')
->whereNull('transaction_journals.deleted_at')
->whereNull('source.deleted_at')
// #10507 ignore opening balance.
->where('transaction_types.type', '!=', TransactionTypeEnum::OPENING_BALANCE->value)
->whereNotNull('transaction_groups.id')
->whereNull('destination.deleted_at')
->orderBy('transaction_journals.date', 'DESC')

View File

@@ -412,7 +412,7 @@ class ProfileController extends Controller
// found user.which email address to return to?
$set = app('preferences')->beginsWith($user, 'previous_email_');
/** @var string $match */
/** @var null|string $match */
$match = null;
foreach ($set as $entry) {
$hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $entry->data));

View File

@@ -117,7 +117,7 @@ class BulkController extends Controller
// run rules on changed journals:
/** @var TransactionJournal $journal */
foreach ($collection as $journal) {
foreach ($collection as $journal) { // @phpstan-ignore-line
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, false));
}

View File

@@ -25,14 +25,15 @@ declare(strict_types=1);
namespace FireflyIII\Http\Middleware;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\Models\Webhook;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Http\Request;
@@ -103,7 +104,7 @@ class InterestingMessage
// send message about newly created transaction group.
/** @var null|TransactionGroup $group */
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int) $transactionGroupId);
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int)$transactionGroupId);
if (null === $group) {
return;
@@ -119,17 +120,17 @@ class InterestingMessage
$title = $count > 1 ? $group->title : $journal->description;
if ('created' === $message) {
session()->flash('success_url', route('transactions.show', [$transactionGroupId]));
session()->flash('success', (string) trans('firefly.stored_journal', ['description' => $title]));
session()->flash('success', (string)trans('firefly.stored_journal', ['description' => $title]));
}
if ('updated' === $message) {
$type = strtolower((string) $journal->transactionType->type);
$type = strtolower((string)$journal->transactionType->type);
session()->flash('success_url', route('transactions.show', [$transactionGroupId]));
session()->flash('success', (string) trans(sprintf('firefly.updated_%s', $type), ['description' => $title]));
session()->flash('success', (string)trans(sprintf('firefly.updated_%s', $type), ['description' => $title]));
}
if ('no_change' === $message) {
$type = strtolower((string) $journal->transactionType->type);
$type = strtolower((string)$journal->transactionType->type);
session()->flash('warning_url', route('transactions.show', [$transactionGroupId]));
session()->flash('warning', (string) trans(sprintf('firefly.no_changes_%s', $type), ['description' => $title]));
session()->flash('warning', (string)trans(sprintf('firefly.no_changes_%s', $type), ['description' => $title]));
}
}
@@ -170,13 +171,13 @@ class InterestingMessage
if ('deleted' === $message) {
session()->flash('success', (string) trans('firefly.flash_administration_deleted', ['title' => $userGroup->title]));
session()->flash('success', (string)trans('firefly.flash_administration_deleted', ['title' => $userGroup->title]));
}
if ('created' === $message) {
session()->flash('success', (string) trans('firefly.flash_administration_created', ['title' => $userGroup->title]));
session()->flash('success', (string)trans('firefly.flash_administration_created', ['title' => $userGroup->title]));
}
if ('updated' === $message) {
session()->flash('success', (string) trans('firefly.flash_administration_updated', ['title' => $userGroup->title]));
session()->flash('success', (string)trans('firefly.flash_administration_updated', ['title' => $userGroup->title]));
}
}
@@ -205,13 +206,13 @@ class InterestingMessage
return;
}
if ('deleted' === $message) {
session()->flash('success', (string) trans('firefly.account_deleted', ['name' => $account->name]));
session()->flash('success', (string)trans('firefly.account_deleted', ['name' => $account->name]));
}
if ('created' === $message) {
session()->flash('success', (string) trans('firefly.stored_new_account', ['name' => $account->name]));
session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
}
if ('updated' === $message) {
session()->flash('success', (string) trans('firefly.updated_account', ['name' => $account->name]));
session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name]));
}
}
@@ -237,10 +238,10 @@ class InterestingMessage
return;
}
if ('deleted' === $message) {
session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $bill->name]));
session()->flash('success', (string)trans('firefly.deleted_bill', ['name' => $bill->name]));
}
if ('created' === $message) {
session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name]));
session()->flash('success', (string)trans('firefly.stored_new_bill', ['name' => $bill->name]));
}
}
@@ -266,13 +267,13 @@ class InterestingMessage
return;
}
if ('deleted' === $message) {
session()->flash('success', (string) trans('firefly.deleted_webhook', ['title' => $webhook->title]));
session()->flash('success', (string)trans('firefly.deleted_webhook', ['title' => $webhook->title]));
}
if ('updated' === $message) {
session()->flash('success', (string) trans('firefly.updated_webhook', ['title' => $webhook->title]));
session()->flash('success', (string)trans('firefly.updated_webhook', ['title' => $webhook->title]));
}
if ('created' === $message) {
session()->flash('success', (string) trans('firefly.stored_new_webhook', ['title' => $webhook->title]));
session()->flash('success', (string)trans('firefly.stored_new_webhook', ['title' => $webhook->title]));
}
}
@@ -289,32 +290,32 @@ class InterestingMessage
{
// params:
// get parameters from request.
$code = $request->get('code');
$message = $request->get('message');
$code = (string) $request->get('code');
$message = (string) $request->get('message');
/** @var null|TransactionCurrency $currency */
$currency = TransactionCurrency::whereCode($code)->first();
if (null === $currency) {
try {
$currency = Amount::getTransactionCurrencyByCode($code);
} catch (FireflyException) {
return;
}
if ('enabled' === $message) {
session()->flash('success', (string) trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
session()->flash('success', (string)trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
}
if ('enable_failed' === $message) {
session()->flash('error', (string) trans('firefly.could_not_enable_currency', ['name' => $currency->name]));
session()->flash('error', (string)trans('firefly.could_not_enable_currency', ['name' => $currency->name]));
}
if ('disabled' === $message) {
session()->flash('success', (string) trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
session()->flash('success', (string)trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
}
if ('disable_failed' === $message) {
session()->flash('error', (string) trans('firefly.could_not_disable_currency', ['name' => $currency->name]));
session()->flash('error', (string)trans('firefly.could_not_disable_currency', ['name' => $currency->name]));
}
if ('default' === $message) {
session()->flash('success', (string) trans('firefly.new_default_currency', ['name' => $currency->name]));
session()->flash('success', (string)trans('firefly.new_default_currency', ['name' => $currency->name]));
}
if ('default_failed' === $message) {
session()->flash('error', (string) trans('firefly.default_currency_failed', ['name' => $currency->name]));
session()->flash('error', (string)trans('firefly.default_currency_failed', ['name' => $currency->name]));
}
}
}

View File

@@ -23,6 +23,8 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests;
use Illuminate\Validation\Validator;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount;
@@ -31,7 +33,6 @@ use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class PiggyBankStoreRequest.
@@ -60,7 +61,7 @@ class PiggyBankStoreRequest extends FormRequest
$accounts = [];
}
foreach ($accounts as $item) {
$data['accounts'][] = ['account_id' => (int) $item];
$data['accounts'][] = ['account_id' => (int)$item];
}
return $data;
@@ -97,7 +98,7 @@ class PiggyBankStoreRequest extends FormRequest
$repository = app(AccountRepositoryInterface::class);
$types = config('firefly.piggy_bank_account_types');
foreach ($data['accounts'] as $value) {
$accountId = (int) $value;
$accountId = (int)$value;
$account = $repository->find($accountId);
if (null !== $account) {
// check currency here.
@@ -123,9 +124,11 @@ class PiggyBankStoreRequest extends FormRequest
private function getCurrencyFromData(array $data): TransactionCurrency
{
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
$currencyId = (int)($data['transaction_currency_id'] ?? 0);
try {
$currency = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {
return Amount::getPrimaryCurrency();
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests;
use Illuminate\Validation\Validator;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -129,8 +130,10 @@ class PiggyBankUpdateRequest extends FormRequest
private function getCurrencyFromData(array $data): TransactionCurrency
{
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
try {
$currency = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {
return Amount::getPrimaryCurrency();
}

View File

@@ -138,7 +138,7 @@ class RecurrenceFormRequest extends FormRequest
* @var int $index
* @var array $transaction
*/
foreach ($return['transactions'] as $index => $transaction) {
foreach ($return['transactions'] as $index => $transaction) { // @phpstan-ignore-line
$categoryName = $transaction['category_name'] ?? null;
if (null !== $categoryName) {
$category = $factory->findOrCreate(null, $categoryName);

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Notifications\Admin;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Bus\Queueable;
@@ -35,7 +34,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class UnknownUserLoginAttempt extends Notification
{

View File

@@ -27,7 +27,6 @@ namespace FireflyIII\Notifications\Admin;
use FireflyIII\Models\InvitedUser;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
@@ -36,7 +35,6 @@ use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class UserInvitation

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Notifications\Admin;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -36,7 +35,6 @@ use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class UserRegistration

View File

@@ -26,14 +26,12 @@ namespace FireflyIII\Notifications\Admin;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class VersionCheckResult

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class DisabledMFANotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class EnabledMFANotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class MFABackupFewLeftNotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class MFABackupNoLeftNotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class MFAManyFailedAttemptsNotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class MFAUsedBackupCodeNotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class NewBackupCodesNotification extends Notification
{

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Security;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
@@ -35,7 +34,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
class UserFailedLoginAttempt extends Notification
{

View File

@@ -25,11 +25,8 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Test;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\ReturnsSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Ntfy\Message;
use Wijourdil\NtfyNotificationChannel\Channels\NtfyChannel;
// use Illuminate\Notifications\Slack\SlackMessage;

View File

@@ -24,12 +24,9 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Test;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Ntfy\Message;
use Wijourdil\NtfyNotificationChannel\Channels\NtfyChannel;
// use Illuminate\Notifications\Slack\SlackMessage;

View File

@@ -26,14 +26,12 @@ namespace FireflyIII\Notifications\User;
use FireflyIII\Models\Bill;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class BillReminder

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
@@ -35,7 +34,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class NewAccessToken

View File

@@ -25,13 +25,11 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class RuleActionFailed

View File

@@ -27,7 +27,6 @@ namespace FireflyIII\Notifications\User;
use Carbon\Carbon;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
@@ -63,9 +62,7 @@ class SubscriptionsOverdueReminder extends Notification
'bill' => $item['bill'],
];
$current['pay_dates'] = array_map(
static function (string $date): string {
return new Carbon($date)->isoFormat((string)trans('config.month_and_day_moment_js'));
},
static fn (string $date): string => new Carbon($date)->isoFormat((string)trans('config.month_and_day_moment_js')),
$item['dates']['pay_dates']
);
$info[] = $current;

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class UserLogin

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\Notifications\ReturnsSettings;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
@@ -34,7 +33,6 @@ use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Request;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
/**
* Class UserNewPassword

View File

@@ -38,6 +38,7 @@ use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
@@ -400,7 +401,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
}
$currencyId = (int) $this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) {
return TransactionCurrency::find($currencyId);
return Amount::getTransactionCurrencyById($currencyId);
}
return null;

View File

@@ -166,7 +166,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$currencyDecimalPlaces = $journal['currency_decimal_places'];
}
if (true === $convertToPrimary && $journalCurrencyId !== $currencyId) {
$currencies[$journalCurrencyId] ??= TransactionCurrency::find($journalCurrencyId);
$currencies[$journalCurrencyId] ??= Amount::getTransactionCurrencyById($journalCurrencyId);
$amount = $converter->convert($currencies[$journalCurrencyId], $primaryCurrency, $journal['date'], $amount);
}
@@ -294,9 +294,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$summarizer->setConvertToPrimary($convertToPrimary);
// filter $journals by range AND currency if it is present.
$expenses = array_filter($expenses, static function (array $expense) use ($start, $end, $transactionCurrency): bool {
return $expense['date']->between($start, $end) && $expense['currency_id'] === $transactionCurrency->id;
});
$expenses = array_filter($expenses, static fn (array $expense): bool => $expense['date']->between($start, $end) && $expense['currency_id'] === $transactionCurrency->id);
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
}
@@ -308,9 +306,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$summarizer->setConvertToPrimary($convertToPrimary);
// filter $journals by range AND currency if it is present.
$expenses = array_filter($expenses, static function (array $expense) use ($budget): bool {
return $expense['budget_id'] === $budget->id;
});
$expenses = array_filter($expenses, static fn (array $expense): bool => $expense['budget_id'] === $budget->id);
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
}

View File

@@ -38,6 +38,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\CurrencyDestroyService;
use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
@@ -84,7 +85,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
}
// 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) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -92,7 +93,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
}
// 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) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -183,7 +184,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
return $all->map(static function (TransactionCurrency $current) use ($local) {
$hasId = $local->contains(static fn (TransactionCurrency $entry) => $entry->id === $current->id);
$isPrimary = $local->contains(static fn (TransactionCurrency $entry) => 1 === (int) $entry->pivot->group_default && $entry->id === $current->id);
$isPrimary = $local->contains(static fn (TransactionCurrency $entry) => 1 === (int)$entry->pivot->group_default && $entry->id === $current->id);
$current->userGroupEnabled = $hasId;
$current->userGroupNative = $isPrimary;
@@ -196,7 +197,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
$all = $this->userGroup->currencies()->orderBy('code', 'ASC')->withPivot(['group_default'])->get();
$all->map(static function (TransactionCurrency $current) { // @phpstan-ignore-line
$current->userGroupEnabled = true;
$current->userGroupNative = 1 === (int) $current->pivot->group_default;
$current->userGroupNative = 1 === (int)$current->pivot->group_default;
return $current;
});
@@ -261,14 +262,14 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
public function findCurrencyNull(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{
Log::debug(sprintf('Now in findCurrencyNull(%s, "%s")', var_export($currencyId, true), $currencyCode));
$result = $this->find((int) $currencyId);
$result = $this->find((int)$currencyId);
if ($result instanceof TransactionCurrency) {
Log::debug(sprintf('Found currency by ID: %s', $result->code));
return $result;
}
Log::debug(sprintf('Searching for currency with code "%s"...', $currencyCode));
$result = $this->findByCode((string) $currencyCode);
$result = $this->findByCode((string)$currencyCode);
if ($result instanceof TransactionCurrency && false === $result->enabled) {
Log::debug(sprintf('Also enabled currency %s', $result->code));
@@ -282,7 +283,13 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
#[Override]
public function find(int $currencyId): ?TransactionCurrency
{
return TransactionCurrency::find($currencyId);
try {
$result = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {
return null;
}
return $result;
}
/**
@@ -290,7 +297,13 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
try {
$result = Amount::getTransactionCurrencyByCode($currencyCode);
} catch (FireflyException) {
return null;
}
return $result;
}
public function enable(TransactionCurrency $currency): void

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PiggyBank;
use Exception;
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Events\Model\PiggyBank\ChangedName;
use FireflyIII\Exceptions\FireflyException;
@@ -32,12 +33,11 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
use Exception;
/**
* Trait ModifiesPiggyBanks
@@ -287,10 +287,8 @@ trait ModifiesPiggyBanks
$piggyBank->name = $data['name'];
}
if (array_key_exists('transaction_currency_id', $data) && is_int($data['transaction_currency_id'])) {
$currency = TransactionCurrency::find($data['transaction_currency_id']);
if (null !== $currency) {
$piggyBank->transaction_currency_id = $currency->id;
}
$currency = Amount::getTransactionCurrencyById($data['transaction_currency_id']);
$piggyBank->transaction_currency_id = $currency->id;
}
if (array_key_exists('target_amount', $data) && '' !== $data['target_amount']) {

View File

@@ -36,7 +36,6 @@ use FireflyIII\Models\Location;
use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalLink;
@@ -354,7 +353,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
->first()
;
if (null !== $currencyPreference) {
$currency = TransactionCurrency::where('id', $currencyPreference->data)->first();
$currency = Amount::getTransactionCurrencyById((int) $currencyPreference->data);
}
$journalId = $row->transaction_journal_id;
$return[$journalId] ??= [];

View File

@@ -137,13 +137,10 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
if (!$existingGroup instanceof UserGroup) {
$exists = false;
/** @var null|UserGroup $existingGroup */
/** @var UserGroup $existingGroup */
$existingGroup = $this->store(['user' => $user, 'title' => $groupName]);
}
if (null !== $existingGroup) {
// group already exists
$groupName = sprintf('%s-%s', $user->email, substr(sha1(random_int(1000, 9999).microtime()), 0, 4));
}
$groupName = sprintf('%s-%s', $user->email, substr(sha1(random_int(1000, 9999).microtime()), 0, 4));
++$loop;
}
@@ -206,7 +203,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
if (array_key_exists('primary_currency_id', $data) && null === $currency) {
$repository->setUser($this->user);
$currency = $repository->find((int) $data['primary_currency_id']);
$currency = $repository->find((int)$data['primary_currency_id']);
}
if (null !== $currency) {
$repository->makePrimary($currency);
@@ -233,7 +230,7 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
$user = User::find($data['id']);
app('log')->debug('Found user by ID');
}
if (array_key_exists('email', $data) && '' !== (string) $data['email']) {
if (array_key_exists('email', $data) && '' !== (string)$data['email']) {
/** @var null|User $user */
$user = User::whereEmail($data['email'])->first();
app('log')->debug('Found user by email');
@@ -251,13 +248,13 @@ class UserGroupRepository implements UserGroupRepositoryInterface, UserGroupInte
if (1 === $membershipCount) {
$lastUserId = $userGroup->groupMemberships()->distinct()->first(['group_memberships.user_id'])->user_id;
// if this is also the user we're editing right now, and we remove all of their roles:
if ($lastUserId === (int) $user->id && 0 === count($data['roles'])) {
if ($lastUserId === (int)$user->id && 0 === count($data['roles'])) {
app('log')->debug('User is last in this group, refuse to act');
throw new FireflyException('You cannot remove the last member from this user group. Delete the user group instead.');
}
// if this is also the user we're editing right now, and do not grant them the owner role:
if ($lastUserId === (int) $user->id && count($data['roles']) > 0 && !in_array(UserRoleEnum::OWNER->value, $data['roles'], true)) {
if ($lastUserId === (int)$user->id && count($data['roles']) > 0 && !in_array(UserRoleEnum::OWNER->value, $data['roles'], true)) {
app('log')->debug('User needs to have owner role in this group, refuse to act');
throw new FireflyException('The last member in this user group must get or keep the "owner" role.');

View File

@@ -1,414 +0,0 @@
<?php
/*
* AccountRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Account;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Override;
use stdClass;
use function Safe\json_encode;
/**
* Class AccountRepository
*
* @deprecated
*/
class AccountRepository implements AccountRepositoryInterface
{
use UserGroupTrait;
#[Override]
public function countAccounts(array $types): int
{
$query = $this->userGroup->accounts();
if (0 !== count($types)) {
$query->accountTypeIn($types);
}
return $query->count();
}
public function findByAccountNumber(string $number, array $types): ?Account
{
$dbQuery = $this->userGroup
->accounts()
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('accounts.active', true)
->where(
static function (EloquentBuilder $q1) use ($number): void {
$json = json_encode($number);
$q1->where('account_meta.name', '=', 'account_number');
$q1->where('account_meta.data', '=', $json);
}
)
;
if (0 !== count($types)) {
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$dbQuery->whereIn('account_types.type', $types);
}
/** @var null|Account */
return $dbQuery->first(['accounts.*']);
}
public function findByIbanNull(string $iban, array $types): ?Account
{
$iban = Steam::filterSpaces($iban);
$query = $this->userGroup->accounts()->where('iban', '!=', '')->whereNotNull('iban');
if (0 !== count($types)) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
/** @var null|Account */
return $query->where('iban', $iban)->first(['accounts.*']);
}
public function findByName(string $name, array $types): ?Account
{
$query = $this->userGroup->accounts();
if (0 !== count($types)) {
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$query->whereIn('account_types.type', $types);
}
app('log')->debug(sprintf('Searching for account named "%s" (of user #%d) of the following type(s)', $name, $this->user->id), ['types' => $types]);
$query->where('accounts.name', $name);
/** @var null|Account $account */
$account = $query->first(['accounts.*']);
if (null === $account) {
app('log')->debug(sprintf('There is no account with name "%s" of types', $name), $types);
return null;
}
app('log')->debug(sprintf('Found #%d (%s) with type id %d', $account->id, $account->name, $account->account_type_id));
return $account;
}
#[Override]
public function getAccountBalances(Account $account): Collection
{
return $account->accountBalances;
}
public function getAccountCurrency(Account $account): ?TransactionCurrency
{
$type = $account->accountType->type;
$list = config('firefly.valid_currency_account_types');
// return null if not in this list.
if (!in_array($type, $list, true)) {
return null;
}
$currencyId = (int) $this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) {
return TransactionCurrency::find($currencyId);
}
return null;
}
/**
* Return meta value for account. Null if not found.
*/
public function getMetaValue(Account $account, string $field): ?string
{
$result = $account->accountMeta->filter(
static fn (AccountMeta $meta) => strtolower($meta->name) === strtolower($field)
);
if (0 === $result->count()) {
return null;
}
if (1 === $result->count()) {
return (string) $result->first()->data;
}
return null;
}
public function find(int $accountId): ?Account
{
$account = $this->user->accounts()->find($accountId);
if (null === $account) {
/** @var null|Account */
return $this->userGroup->accounts()->find($accountId);
}
/** @var null|Account */
return $account;
}
#[Override]
public function getAccountTypes(Collection $accounts): Collection
{
return AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accounts->pluck('id')->toArray())
->get(['accounts.id', 'account_types.type'])
;
}
public function getAccountsById(array $accountIds): Collection
{
$query = $this->userGroup->accounts();
if (0 !== count($accountIds)) {
$query->whereIn('accounts.id', $accountIds);
}
$query->orderBy('accounts.order', 'ASC');
$query->orderBy('accounts.active', 'DESC');
$query->orderBy('accounts.name', 'ASC');
return $query->get(['accounts.*']);
}
#[Override]
public function getAccountsInOrder(array $types, array $sort, int $startRow, int $endRow): Collection
{
$query = $this->userGroup->accounts();
if (0 !== count($types)) {
$query->accountTypeIn($types);
}
$query->skip($startRow);
$query->take($endRow - $startRow);
// add sort parameters. At this point they're filtered to allowed fields to sort by:
if (0 !== count($sort)) {
foreach ($sort as $label => $direction) {
$query->orderBy(sprintf('accounts.%s', $label), $direction);
}
}
if (0 === count($sort)) {
$query->orderBy('accounts.order', 'ASC');
$query->orderBy('accounts.active', 'DESC');
$query->orderBy('accounts.name', 'ASC');
}
return $query->get(['accounts.*']);
}
public function getActiveAccountsByType(array $types): Collection
{
$query = $this->userGroup->accounts();
if (0 !== count($types)) {
$query->accountTypeIn($types);
}
$query->where('active', true);
$query->orderBy('accounts.account_type_id', 'ASC');
$query->orderBy('accounts.order', 'ASC');
$query->orderBy('accounts.name', 'ASC');
return $query->get(['accounts.*']);
}
#[Override]
public function getLastActivity(Collection $accounts): array
{
return Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')->groupBy('transactions.account_id')->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray();
}
#[Override]
public function getMetaValues(Collection $accounts, array $fields): Collection
{
$query = AccountMeta::whereIn('account_id', $accounts->pluck('id')->toArray());
if (count($fields) > 0) {
$query->whereIn('name', $fields);
}
return $query->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data']);
}
#[Override]
public function getObjectGroups(Collection $accounts): array
{
$groupIds = [];
$return = [];
$set = DB::table('object_groupables')->where('object_groupable_type', Account::class)
->whereIn('object_groupable_id', $accounts->pluck('id')->toArray())->get()
;
/** @var stdClass $row */
foreach ($set as $row) {
$groupIds[] = $row->object_group_id;
}
$groupIds = array_unique($groupIds);
$groups = ObjectGroup::whereIn('id', $groupIds)->get();
/** @var stdClass $row */
foreach ($set as $row) {
if (!array_key_exists($row->object_groupable_id, $return)) {
/** @var null|ObjectGroup $group */
$group = $groups->firstWhere('id', '=', $row->object_group_id);
if (null !== $group) {
$return[$row->object_groupable_id] = ['title' => $group->title, 'order' => $group->order, 'id' => $group->id];
}
}
}
return $return;
}
public function resetAccountOrder(): void
{
$sets = [
[AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value],
[AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::MORTGAGE->value],
];
foreach ($sets as $set) {
$list = $this->getAccountsByType($set);
$index = 1;
foreach ($list as $account) {
if (false === $account->active) {
$account->order = 0;
continue;
}
if ($index !== (int) $account->order) {
app('log')->debug(sprintf('Account #%d ("%s"): order should %d be but is %d.', $account->id, $account->name, $index, $account->order));
$account->order = $index;
$account->save();
}
++$index;
}
}
// reset the rest to zero.
$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')
->whereNotIn('account_types.type', $all)
->update(['order' => 0])
;
}
public function getAccountsByType(array $types, ?array $sort = [], ?array $filters = []): Collection
{
$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);
$query = $this->userGroup->accounts();
if (0 !== count($types)) {
$query->accountTypeIn($types);
}
// process filters
// TODO this should be repeatable, it feels like a hack when you do it here.
// TODO some fields cannot be filtered using the query, and a second filter must be applied on the collection.
foreach ($filters as $column => $value) {
// filter on NULL values
if (null === $value) {
continue;
}
if ('active' === $column) {
$query->where('accounts.active', $value);
}
if ('name' === $column) {
$query->whereLike('accounts.name', sprintf('%%%s%%', $value));
}
}
// add sort parameters. At this point they're filtered to allowed fields to sort by:
$hasActiveColumn = array_key_exists('active', $sort);
if (count($sort) > 0) {
if (false === $hasActiveColumn) {
$query->orderBy('accounts.active', 'DESC');
}
foreach ($sort as $column => $direction) {
if (in_array($column, $sortable, true)) {
$query->orderBy(sprintf('accounts.%s', $column), $direction);
}
}
}
if (0 === count($sort)) {
if (0 !== count($res)) {
$query->orderBy('accounts.active', 'DESC');
}
$query->orderBy('accounts.order', 'ASC');
$query->orderBy('accounts.name', 'ASC');
$query->orderBy('accounts.account_type_id', 'ASC');
$query->orderBy('accounts.id', 'ASC');
}
return $query->get(['accounts.*']);
}
#[Override]
public function update(Account $account, array $data): Account
{
/** @var AccountUpdateService $service */
$service = app(AccountUpdateService::class);
return $service->update($account, $data);
}
public function searchAccount(string $query, array $types, int $page, int $limit): Collection
{
// search by group, not by user
$dbQuery = $this->userGroup->accounts()
->where('active', true)
->orderBy('accounts.updated_at', 'ASC')
->orderBy('accounts.order', 'ASC')
->orderBy('accounts.account_type_id', 'ASC')
->orderBy('accounts.name', 'ASC')
->with(['accountType'])
;
// split query on spaces just in case:
if ('' !== trim($query)) {
$dbQuery->where(function (EloquentBuilder $q) use ($query): void {
$parts = explode(' ', $query);
foreach ($parts as $part) {
$search = sprintf('%%%s%%', $part);
$q->orWhereLike('name', $search);
}
});
}
if (0 !== count($types)) {
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
$dbQuery->whereIn('account_types.type', $types);
}
$dbQuery->skip(($page - 1) * $limit)->take($limit);
return $dbQuery->get(['accounts.*']);
}
}

View File

@@ -1,84 +0,0 @@
<?php
/*
* AccountRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Account;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Support\Collection;
/**
* Interface AccountRepositoryInterface
*
* @deprecated
*/
interface AccountRepositoryInterface
{
public function countAccounts(array $types): int;
public function find(int $accountId): ?Account;
public function findByAccountNumber(string $number, array $types): ?Account;
public function findByIbanNull(string $iban, array $types): ?Account;
public function findByName(string $name, array $types): ?Account;
public function getAccountBalances(Account $account): Collection;
public function getAccountCurrency(Account $account): ?TransactionCurrency;
public function getAccountTypes(Collection $accounts): Collection;
public function getAccountsById(array $accountIds): Collection;
public function getAccountsByType(array $types, ?array $sort = [], ?array $filters = []): Collection;
/**
* Used in the infinite accounts list.
*/
public function getAccountsInOrder(array $types, array $sort, int $startRow, int $endRow): Collection;
public function getActiveAccountsByType(array $types): Collection;
public function getLastActivity(Collection $accounts): array;
/**
* Return meta value for account. Null if not found.
*/
public function getMetaValue(Account $account, string $field): ?string;
public function getMetaValues(Collection $accounts, array $fields): Collection;
public function getObjectGroups(Collection $accounts): array;
/**
* Reset order types of the mentioned accounts.
*/
public function resetAccountOrder(): void;
public function searchAccount(string $query, array $types, int $page, int $limit): Collection;
public function update(Account $account, array $data): Account;
}

View File

@@ -1,236 +0,0 @@
<?php
/*
* BillRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Bill;
use Carbon\Carbon;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class BillRepository
*
* @deprecated
*/
class BillRepository implements BillRepositoryInterface
{
use UserGroupTrait;
/**
* Correct order of piggies in case of issues.
*/
public function correctOrder(): void
{
$set = $this->userGroup->bills()->orderBy('order', 'ASC')->get();
$current = 1;
foreach ($set as $bill) {
if ($bill->order !== $current) {
$bill->order = $current;
$bill->save();
}
++$current;
}
}
public function getBills(): Collection
{
return $this->userGroup->bills()
->orderBy('bills.name', 'ASC')
->get(['bills.*'])
;
}
public function sumPaidInRange(Carbon $start, Carbon $end): array
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$bills = $this->getActiveBills();
$primary = app('amount')->getPrimaryCurrency();
$return = [];
$converter = new ExchangeRateConverter();
/** @var Bill $bill */
foreach ($bills as $bill) {
/** @var Collection $set */
$set = $bill->transactionJournals()->after($start)->before($end)->get(['transaction_journals.*']);
$currency = $bill->transactionCurrency;
$currencyId = $bill->transaction_currency_id;
$return[$currencyId] ??= [
'currency_id' => (string) $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'primary_currency_id' => (string) $primary->id,
'primary_currency_name' => $primary->name,
'primary_currency_symbol' => $primary->symbol,
'primary_currency_code' => $primary->code,
'primary_currency_decimal_places' => $primary->decimal_places,
'sum' => '0',
'pc_sum' => '0',
];
/** @var TransactionJournal $transactionJournal */
foreach ($set as $transactionJournal) {
/** @var null|Transaction $sourceTransaction */
$sourceTransaction = $transactionJournal->transactions()->where('amount', '<', 0)->first();
if (null !== $sourceTransaction) {
$amount = $sourceTransaction->amount;
if ((int) $sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead!
$amount = (string) $sourceTransaction->foreign_amount;
}
// convert to primary currency
$pcAmount = $amount;
if ($currencyId !== $primary->id) {
// get rate and convert.
$pcAmount = $converter->convert($currency, $primary, $transactionJournal->date, $amount);
}
if ((int) $sourceTransaction->foreign_currency_id === $primary->id) {
// ignore conversion, use foreign amount
$pcAmount = (string) $sourceTransaction->foreign_amount;
}
$return[$currencyId]['sum'] = bcadd($return[$currencyId]['sum'], (string) $amount);
$return[$currencyId]['pc_sum'] = bcadd($return[$currencyId]['pc_sum'], (string) $pcAmount);
}
}
}
$converter->summarize();
return $return;
}
public function getActiveBills(): Collection
{
return $this->userGroup->bills()
->where('active', true)
->orderBy('bills.name', 'ASC')
->get(['bills.*'])
;
}
public function sumUnpaidInRange(Carbon $start, Carbon $end): array
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$bills = $this->getActiveBills();
$return = [];
$primary = app('amount')->getPrimaryCurrency();
$converter = new ExchangeRateConverter();
/** @var Bill $bill */
foreach ($bills as $bill) {
$dates = $this->getPayDatesInRange($bill, $start, $end);
$count = $bill->transactionJournals()->after($start)->before($end)->count();
$total = $dates->count() - $count;
if ($total > 0) {
$currency = $bill->transactionCurrency;
$currencyId = $bill->transaction_currency_id;
$average = bcdiv(bcadd((string) $bill->amount_max, (string) $bill->amount_min), '2');
$pcAverage = $converter->convert($currency, $primary, $start, $average);
$return[$currencyId] ??= [
'currency_id' => (string) $currency->id,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'currency_decimal_places' => $currency->decimal_places,
'primary_currency_id' => (string) $primary->id,
'primary_currency_name' => $primary->name,
'primary_currency_symbol' => $primary->symbol,
'primary_currency_code' => $primary->code,
'primary_currency_decimal_places' => $primary->decimal_places,
'sum' => '0',
'pc_sum' => '0',
];
$return[$currencyId]['sum'] = bcadd($return[$currencyId]['sum'], bcmul($average, (string) $total));
$return[$currencyId]['pc_sum'] = bcadd($return[$currencyId]['pc_sum'], bcmul($pcAverage, (string) $total));
}
}
$converter->summarize();
return $return;
}
/**
* Between start and end, tells you on which date(s) the bill is expected to hit.
* TODO duplicate of function in other billrepositoryinterface
*/
public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection
{
$set = new Collection();
$currentStart = clone $start;
// app('log')->debug(sprintf('Now at bill "%s" (%s)', $bill->name, $bill->repeat_freq));
// app('log')->debug(sprintf('First currentstart is %s', $currentStart->format('Y-m-d')));
while ($currentStart <= $end) {
// app('log')->debug(sprintf('Currentstart is now %s.', $currentStart->format('Y-m-d')));
$nextExpectedMatch = $this->nextDateMatch($bill, $currentStart);
// app('log')->debug(sprintf('Next Date match after %s is %s', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
if ($nextExpectedMatch > $end) {// If nextExpectedMatch is after end, we continue
break;
}
$set->push(clone $nextExpectedMatch);
// app('log')->debug(sprintf('Now %d dates in set.', $set->count()));
$nextExpectedMatch->addDay();
// app('log')->debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
$currentStart = clone $nextExpectedMatch;
}
return $set;
}
/**
* Given a bill and a date, this method will tell you at which moment this bill expects its next
* transaction. Whether it is there already, is not relevant.
*
* TODO duplicate of other repos
*/
public function nextDateMatch(Bill $bill, Carbon $date): Carbon
{
$cache = new CacheProperties();
$cache->addProperty($bill->id);
$cache->addProperty('nextDateMatch');
$cache->addProperty($date);
if ($cache->has()) {
return $cache->get();
}
// find the most recent date for this bill NOT in the future. Cache this date:
$start = clone $bill->date;
while ($start < $date) {
$start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
}
$cache->store($start);
return $start;
}
}

View File

@@ -1,72 +0,0 @@
<?php
/*
* BillRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Bill;
use Carbon\Carbon;
use FireflyIII\Models\Bill;
use Illuminate\Support\Collection;
/**
* Interface BillRepositoryInterface
*
* @deprecated
*/
interface BillRepositoryInterface
{
/**
* TODO duplicate of other repos
* Add correct order to bills.
*/
public function correctOrder(): void;
public function getActiveBills(): Collection;
public function getBills(): Collection;
/**
* Between start and end, tells you on which date(s) the bill is expected to hit.
*
* TODO duplicate of method in other billrepositoryinterface
*/
public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection;
/**
* Given a bill and a date, this method will tell you at which moment this bill expects its next
* transaction. Whether it is there already, is not relevant.
*
* TODO duplicate of method in other bill repos
*/
public function nextDateMatch(Bill $bill, Carbon $date): Carbon;
/**
* Collect multi-currency of sum of bills already paid.
*/
public function sumPaidInRange(Carbon $start, Carbon $end): array;
/**
* Collect multi-currency of sum of bills yet to pay.
*/
public function sumUnpaidInRange(Carbon $start, Carbon $end): array;
}

View File

@@ -1,78 +0,0 @@
<?php
/*
* AvailableBudgetRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Budget;
use Carbon\Carbon;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Facades\Log;
/**
* Class AvailableBudgetRepository
*
* @deprecated
*/
class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
{
use UserGroupTrait;
public function getAvailableBudgetWithCurrency(Carbon $start, Carbon $end): array
{
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$return = [];
$converter = new ExchangeRateConverter();
$primary = app('amount')->getPrimaryCurrency();
$availableBudgets = $this->userGroup->availableBudgets()
->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->get()
;
/** @var AvailableBudget $availableBudget */
foreach ($availableBudgets as $availableBudget) {
$currencyId = $availableBudget->transaction_currency_id;
$return[$currencyId] ??= [
'currency_id' => $currencyId,
'currency_code' => $availableBudget->transactionCurrency->code,
'currency_symbol' => $availableBudget->transactionCurrency->symbol,
'currency_name' => $availableBudget->transactionCurrency->name,
'currency_decimal_places' => $availableBudget->transactionCurrency->decimal_places,
'primary_currency_id' => $primary->id,
'primary_currency_code' => $primary->code,
'primary_currency_symbol' => $primary->symbol,
'primary_currency_name' => $primary->name,
'primary_currency_decimal_places' => $primary->decimal_places,
'amount' => '0',
'pc_amount' => '0',
];
$pcAmount = $converter->convert($availableBudget->transactionCurrency, $primary, $availableBudget->start_date, $availableBudget->amount);
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], (string) $availableBudget->amount);
$return[$currencyId]['pc_amount'] = bcadd($return[$currencyId]['pc_amount'], $pcAmount);
}
$converter->summarize();
return $return;
}
}

View File

@@ -1,37 +0,0 @@
<?php
/*
* AvailableBudgetRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Budget;
use Carbon\Carbon;
/**
* Interface AvailableBudgetRepositoryInterface
*
* @deprecated
*/
interface AvailableBudgetRepositoryInterface
{
public function getAvailableBudgetWithCurrency(Carbon $start, Carbon $end): array;
}

View File

@@ -1,56 +0,0 @@
<?php
/*
* BudgetRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Budget;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
/**
* Class BudgetRepository
*
* @deprecated
*/
class BudgetRepository implements BudgetRepositoryInterface
{
use UserGroupTrait;
public function getActiveBudgets(): Collection
{
return $this->userGroup->budgets()->where('active', true)
->orderBy('order', 'ASC')
->orderBy('name', 'ASC')
->get()
;
}
public function getBudgets(): Collection
{
return $this->userGroup->budgets()
->orderBy('order', 'ASC')
->orderBy('name', 'ASC')
->get()
;
}
}

View File

@@ -1,39 +0,0 @@
<?php
/*
* BudgetRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Budget;
use Illuminate\Support\Collection;
/**
* Interface BudgetRepositoryInterface
*
* @deprecated
*/
interface BudgetRepositoryInterface
{
public function getActiveBudgets(): Collection;
public function getBudgets(): Collection;
}

View File

@@ -1,136 +0,0 @@
<?php
/*
* OperationsRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Budget;
use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
/**
* Class OperationsRepository
*
* @deprecated
*/
class OperationsRepository implements OperationsRepositoryInterface
{
use UserGroupTrait;
/**
* @throws FireflyException
*/
public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUserGroup($this->userGroup)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
if ($accounts instanceof Collection && $accounts->count() > 0) {
$collector->setAccounts($accounts);
}
if ($budgets instanceof Collection && $budgets->count() > 0) {
$collector->setBudgets($budgets);
}
if (!$budgets instanceof Collection || (0 === $budgets->count())) {
$collector->setBudgets($this->getBudgets());
}
$collector->withBudgetInformation()->withAccountInformation()->withCategoryInformation();
$journals = $collector->getExtractedJournals();
$array = [];
foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id'];
$budgetId = (int) $journal['budget_id'];
$budgetName = (string) $journal['budget_name'];
// catch "no budget" entries.
if (0 === $budgetId) {
continue;
}
// info about the currency:
$array[$currencyId] ??= [
'budgets' => [],
'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
// info about the budgets:
$array[$currencyId]['budgets'][$budgetId] ??= [
'id' => $budgetId,
'name' => $budgetName,
'transaction_journals' => [],
];
// add journal to array:
// only a subset of the fields.
$journalId = (int) $journal['transaction_journal_id'];
$final = [
'amount' => app('steam')->negative($journal['amount']),
'currency_id' => $journal['currency_id'],
'foreign_amount' => null,
'foreign_currency_id' => null,
'foreign_currency_code' => null,
'foreign_currency_symbol' => null,
'foreign_currency_name' => null,
'foreign_currency_decimal_places' => null,
'destination_account_id' => $journal['destination_account_id'],
'destination_account_name' => $journal['destination_account_name'],
'source_account_id' => $journal['source_account_id'],
'source_account_name' => $journal['source_account_name'],
'category_name' => $journal['category_name'],
'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'],
'date' => $journal['date'],
];
if (null !== $journal['foreign_amount']) {
$final['foreign_amount'] = app('steam')->negative($journal['foreign_amount']);
$final['foreign_currency_id'] = $journal['foreign_currency_id'];
$final['foreign_currency_code'] = $journal['foreign_currency_code'];
$final['foreign_currency_symbol'] = $journal['foreign_currency_symbol'];
$final['foreign_currency_name'] = $journal['foreign_currency_name'];
$final['foreign_currency_decimal_places'] = $journal['foreign_currency_decimal_places'];
}
$array[$currencyId]['budgets'][$budgetId]['transaction_journals'][$journalId] = $final;
}
return $array;
}
private function getBudgets(): Collection
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$repository->setUserGroup($this->getUserGroup());
return $repository->getActiveBudgets();
}
}

View File

@@ -1,43 +0,0 @@
<?php
/*
* OperationsRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Budget;
use Carbon\Carbon;
use Illuminate\Support\Collection;
/**
* Interface OperationsRepositoryInterface
*
* @deprecated
*/
interface OperationsRepositoryInterface
{
/**
* This method returns a list of all the withdrawal transaction journals (as arrays) set in that period
* which have the specified budget set to them. It's grouped per currency, with as few details in the array
* as possible. Amounts are always negative.
*/
public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null): array;
}

View File

@@ -1,58 +0,0 @@
<?php
/*
* CategoryRepository.php
* Copyright (c) 2024 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Category;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
/**
* Class CategoryRepository
*
* @deprecated
*/
class CategoryRepository implements CategoryRepositoryInterface
{
use UserGroupTrait;
public function searchCategory(array $query, int $limit): Collection
{
$search = $this->userGroup->categories();
if (count($query) > 0) {
// split query on spaces just in case:
$search->where(function (EloquentBuilder $q) use ($query): void {
foreach ($query as $line) {
$parts = explode(' ', $line);
foreach ($parts as $part) {
$search = sprintf('%%%s%%', $part);
$q->orWhereLike('name', $search);
}
}
});
}
return $search->take($limit)->get();
}
}

View File

@@ -1,40 +0,0 @@
<?php
/*
* CategoryRepositoryInterface.php
* Copyright (c) 2024 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Category;
use Illuminate\Support\Collection;
/**
* Interface CategoryRepositoryInterface
*
* @deprecated
*/
interface CategoryRepositoryInterface
{
/**
* Search for a category using wild cards. Uses the database, so case sensitive.
*/
public function searchCategory(array $query, int $limit): Collection;
}

View File

@@ -1,392 +0,0 @@
<?php
/*
* CurrencyRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Currency;
use FireflyIII\Events\Preferences\UserGroupChangedPrimaryCurrency;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\CurrencyDestroyService;
use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use function Safe\json_encode;
/**
* Class CurrencyRepository
*
* @deprecated
*/
class CurrencyRepository implements CurrencyRepositoryInterface
{
use UserGroupTrait;
/**
* @throws FireflyException
*/
public function currencyInUse(TransactionCurrency $currency): bool
{
$result = $this->currencyInUseAt($currency);
return null !== $result;
}
/**
* @throws FireflyException
*/
public function currencyInUseAt(TransactionCurrency $currency): ?string
{
Log::debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
$countJournals = $this->countJournals($currency);
if ($countJournals > 0) {
Log::info(sprintf('Count journals is %d, return true.', $countJournals));
return 'journals';
}
// is the only currency left
if (1 === $this->getAll()->count()) {
Log::info('Is the last currency in the system, return true. ');
return 'last_left';
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// second search using integer check.
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in bills:
$bills = Bill::where('transaction_currency_id', $currency->id)->count();
if ($bills > 0) {
Log::info(sprintf('Used in %d bills as currency, return true. ', $bills));
return 'bills';
}
// is being used in recurring transactions
$recurringAmount = RecurrenceTransaction::where('transaction_currency_id', $currency->id)->count();
$recurringForeign = RecurrenceTransaction::where('foreign_currency_id', $currency->id)->count();
if ($recurringAmount > 0 || $recurringForeign > 0) {
Log::info(sprintf('Used in %d recurring transactions as (foreign) currency id, return true. ', $recurringAmount + $recurringForeign));
return 'recurring';
}
// is being used in accounts (as integer)
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
->whereNull('accounts.deleted_at')
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode($currency->id))->count()
;
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in available budgets
$availableBudgets = AvailableBudget::where('transaction_currency_id', $currency->id)->count();
if ($availableBudgets > 0) {
Log::info(sprintf('Used in %d available budgets as currency, return true. ', $availableBudgets));
return 'available_budgets';
}
// is being used in budget limits
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
if ($budgetLimit > 0) {
Log::info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit));
return 'budget_limits';
}
// is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) {
Log::info('Is the default currency of the user, return true.');
return 'current_default';
}
// is the default currency for the user or the system
$count = $this->userGroup->currencies()->where('transaction_currencies.id', $currency->id)->wherePivot('group_default', 1)->count();
if ($count > 0) {
Log::info('Is the default currency of the user group, return true.');
return 'current_default';
}
Log::debug('Currency is not used, return false.');
return null;
}
private function countJournals(TransactionCurrency $currency): int
{
$count = $currency->transactions()->whereNull('deleted_at')->count() + $currency->transactionJournals()->whereNull('deleted_at')->count();
// also count foreign:
return $count + Transaction::where('foreign_currency_id', $currency->id)->count();
}
/**
* Returns ALL currencies, regardless of whether they are enabled or not.
*/
public function getAll(): Collection
{
$all = TransactionCurrency::orderBy('code', 'ASC')->get();
$local = $this->get();
return $all->map(static function (TransactionCurrency $current) use ($local) {
$hasId = $local->contains(static fn (TransactionCurrency $entry) => $entry->id === $current->id);
$isPrimary = $local->contains(static fn (TransactionCurrency $entry) => 1 === (int) $entry->pivot->group_default && $entry->id === $current->id);
$current->userGroupEnabled = $hasId;
$current->userGroupNative = $isPrimary;
return $current;
});
}
public function get(): Collection
{
$all = $this->userGroup->currencies()->orderBy('code', 'ASC')->withPivot(['group_default'])->get();
$all->map(static function (TransactionCurrency $current) { // @phpstan-ignore-line
$current->userGroupEnabled = true;
$current->userGroupNative = 1 === (int) $current->pivot->group_default;
return $current;
});
/** @var Collection */
return $all;
}
public function destroy(TransactionCurrency $currency): bool
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole($this->user, 'owner')) {
/** @var CurrencyDestroyService $service */
$service = app(CurrencyDestroyService::class);
$service->destroy($currency);
}
return true;
}
/**
* Disables a currency
*/
public function disable(TransactionCurrency $currency): void
{
$this->userGroup->currencies()->detach($currency->id);
$currency->enabled = false;
$currency->save();
}
public function findByName(string $name): ?TransactionCurrency
{
return TransactionCurrency::where('name', $name)->first();
}
/**
* Find by object, ID or code. Returns user default or system default.
*
* @throws FireflyException
*/
public function findCurrency(?int $currencyId, ?string $currencyCode): TransactionCurrency
{
$result = $this->findCurrencyNull($currencyId, $currencyCode);
if (!$result instanceof TransactionCurrency) {
Log::debug('Grabbing default currency for this user...');
/** @var null|TransactionCurrency $result */
$result = app('amount')->getPrimaryCurrencyByUserGroup($this->user->userGroup);
}
Log::debug(sprintf('Final result: %s', $result->code));
if (false === $result->enabled) {
Log::debug(sprintf('Also enabled currency %s', $result->code));
$this->enable($result);
}
return $result;
}
/**
* Find by object, ID or code. Returns NULL if nothing found.
*/
public function findCurrencyNull(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{
Log::debug(sprintf('Now in findCurrencyNull("%s", "%s")', $currencyId, $currencyCode));
$result = $this->find((int) $currencyId);
if (!$result instanceof TransactionCurrency) {
Log::debug(sprintf('Searching for currency with code "%s"...', $currencyCode));
$result = $this->findByCode((string) $currencyCode);
}
if ($result instanceof TransactionCurrency && false === $result->enabled) {
Log::debug(sprintf('Also enabled currency %s', $result->code));
$this->enable($result);
}
return $result;
}
/**
* Find by ID, return NULL if not found.
*/
public function find(int $currencyId): ?TransactionCurrency
{
return TransactionCurrency::find($currencyId);
}
/**
* Find by currency code, return NULL if unfound.
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
}
public function enable(TransactionCurrency $currency): void
{
$this->userGroup->currencies()->syncWithoutDetaching([$currency->id]);
$currency->enabled = false;
$currency->save();
}
public function getByIds(array $ids): Collection
{
return TransactionCurrency::orderBy('code', 'ASC')->whereIn('id', $ids)->get();
}
public function isFallbackCurrency(TransactionCurrency $currency): bool
{
return $currency->code === config('firefly.default_currency', 'EUR');
}
public function searchCurrency(string $search, int $limit): Collection
{
$query = TransactionCurrency::where('enabled', true);
if ('' !== $search) {
$query->whereLike('name', sprintf('%%%s%%', $search));
}
return $query->take($limit)->get();
}
/**
* @throws FireflyException
*/
public function store(array $data): TransactionCurrency
{
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
$result = $factory->create($data);
if (true === $data['enabled']) {
$this->userGroup->currencies()->attach($result->id);
}
return $result;
}
public function update(TransactionCurrency $currency, array $data): TransactionCurrency
{
Log::debug('Now in update()');
// can be true, false, null
$enabled = array_key_exists('enabled', $data) ? $data['enabled'] : null;
// can be true, false, but method only responds to "true".
$default = array_key_exists('default', $data) ? $data['default'] : false;
// remove illegal combo's:
if (false === $enabled && true === $default) {
$enabled = true;
}
// update currency with current user specific settings
$currency->refreshForUser($this->user);
// currency is enabled, must be disabled.
if (false === $enabled) {
Log::debug(sprintf('Disabled currency %s for user #%d', $currency->code, $this->userGroup->id));
$this->userGroup->currencies()->detach($currency->id);
}
// currency must be enabled
if (true === $enabled) {
Log::debug(sprintf('Enabled currency %s for user #%d', $currency->code, $this->userGroup->id));
$this->userGroup->currencies()->detach($currency->id);
$this->userGroup->currencies()->syncWithoutDetaching([$currency->id => ['group_default' => false]]);
}
// currency must be made default.
if (true === $default) {
$this->makePrimary($currency);
}
/** @var CurrencyUpdateService $service */
$service = app(CurrencyUpdateService::class);
return $service->update($currency, $data);
}
public function makePrimary(TransactionCurrency $currency): void
{
$current = app('amount')->getPrimaryCurrencyByUserGroup($this->userGroup);
Log::debug(sprintf('Enabled + made default currency %s for user #%d', $currency->code, $this->userGroup->id));
$this->userGroup->currencies()->detach($currency->id);
foreach ($this->userGroup->currencies()->get() as $item) {
$this->userGroup->currencies()->updateExistingPivot($item->id, ['group_default' => false]);
}
$this->userGroup->currencies()->syncWithoutDetaching([$currency->id => ['group_default' => true]]);
if ($current->id !== $currency->id) {
Log::debug('Trigger on a different default currency.');
// clear all primary currency amounts through an event.
event(new UserGroupChangedPrimaryCurrency($this->userGroup));
}
}
}

View File

@@ -1,102 +0,0 @@
<?php
/*
* CurrencyRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Currency;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Support\Collection;
/**
* Interface CurrencyRepositoryInterface
*
* @deprecated
*/
interface CurrencyRepositoryInterface
{
public function currencyInUse(TransactionCurrency $currency): bool;
/**
* Currency is in use where exactly.
*/
public function currencyInUseAt(TransactionCurrency $currency): ?string;
public function destroy(TransactionCurrency $currency): bool;
/**
* Disables a currency
*/
public function disable(TransactionCurrency $currency): void;
/**
* Enables a currency
*/
public function enable(TransactionCurrency $currency): void;
/**
* Find by ID, return NULL if not found.
*/
public function find(int $currencyId): ?TransactionCurrency;
public function findByCode(string $currencyCode): ?TransactionCurrency;
public function findByName(string $name): ?TransactionCurrency;
/**
* Find by object, ID or code. Returns user default or system default.
*/
public function findCurrency(?int $currencyId, ?string $currencyCode): TransactionCurrency;
/**
* Find by object, ID or code. Returns NULL if nothing found.
*/
public function findCurrencyNull(?int $currencyId, ?string $currencyCode): ?TransactionCurrency;
/**
* Get the user group's currencies.
*
* @return Collection<TransactionCurrency>
*/
public function get(): Collection;
/**
* Get ALL currencies.
*/
public function getAll(): Collection;
public function getByIds(array $ids): Collection;
public function isFallbackCurrency(TransactionCurrency $currency): bool;
public function makePrimary(TransactionCurrency $currency): void;
public function searchCurrency(string $search, int $limit): Collection;
/**
* @throws FireflyException
*/
public function store(array $data): TransactionCurrency;
public function update(TransactionCurrency $currency, array $data): TransactionCurrency;
}

View File

@@ -1,119 +0,0 @@
<?php
/*
* ExchangeRateRepository.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\ExchangeRate;
use Carbon\Carbon;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Override;
/**
* Class ExchangeRateRepository
*
* @deprecated
*/
class ExchangeRateRepository implements ExchangeRateRepositoryInterface
{
use UserGroupTrait;
#[Override]
public function deleteRate(CurrencyExchangeRate $rate): void
{
$this->userGroup->currencyExchangeRates()->where('id', $rate->id)->delete();
}
#[Override]
public function getAll(): Collection
{
return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get();
}
#[Override]
public function getRates(TransactionCurrency $from, TransactionCurrency $to): Collection
{
// orderBy('date', 'DESC')->toRawSql();
return
$this->userGroup->currencyExchangeRates()
->where(function (Builder $q1) use ($from, $to): void {
$q1->where(function (Builder $q) use ($from, $to): void {
$q->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id)
;
})->orWhere(function (Builder $q) use ($from, $to): void {
$q->where('from_currency_id', $to->id)
->where('to_currency_id', $from->id)
;
});
})
->orderBy('date', 'DESC')
->get(['currency_exchange_rates.*'])
;
}
#[Override]
public function getSpecificRateOnDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): ?CurrencyExchangeRate
{
/** @var null|CurrencyExchangeRate */
return
$this->userGroup->currencyExchangeRates()
->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id)
->where('date', $date->format('Y-m-d'))
->first()
;
}
#[Override]
public function storeExchangeRate(TransactionCurrency $from, TransactionCurrency $to, string $rate, Carbon $date): CurrencyExchangeRate
{
$object = new CurrencyExchangeRate();
$object->user_id = auth()->user()->id;
$object->user_group_id = $this->userGroup->id;
$object->from_currency_id = $from->id;
$object->to_currency_id = $to->id;
$object->rate = $rate;
$object->date = $date;
$object->date_tz = $date->format('e');
$object->save();
return $object;
}
#[Override]
public function updateExchangeRate(CurrencyExchangeRate $object, string $rate, ?Carbon $date = null): CurrencyExchangeRate
{
$object->rate = $rate;
if ($date instanceof Carbon) {
$object->date = $date;
}
$object->save();
return $object;
}
}

View File

@@ -1,50 +0,0 @@
<?php
/*
* ExchangeRateRepositoryInterface.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\ExchangeRate;
use Carbon\Carbon;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Support\Collection;
/**
* Interface ExchangeRateRepositoryInterface
*
* @deprecated
*/
interface ExchangeRateRepositoryInterface
{
public function deleteRate(CurrencyExchangeRate $rate): void;
public function getAll(): Collection;
public function getRates(TransactionCurrency $from, TransactionCurrency $to): Collection;
public function getSpecificRateOnDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): ?CurrencyExchangeRate;
public function storeExchangeRate(TransactionCurrency $from, TransactionCurrency $to, string $rate, Carbon $date): CurrencyExchangeRate;
public function updateExchangeRate(CurrencyExchangeRate $object, string $rate, ?Carbon $date = null): CurrencyExchangeRate;
}

View File

@@ -1,60 +0,0 @@
<?php
/*
* JournalRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Journal;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
/**
* Class JournalRepository
*
* @deprecated
*/
class JournalRepository implements JournalRepositoryInterface
{
use UserGroupTrait;
public function searchJournalDescriptions(array $query, int $limit): Collection
{
$search = $this->userGroup->transactionJournals()
->orderBy('date', 'DESC')
;
if (count($query) > 0) {
// split query on spaces just in case:
$search->where(function (EloquentBuilder $q) use ($query): void {
foreach ($query as $line) {
$parts = explode(' ', $line);
foreach ($parts as $part) {
$search = sprintf('%%%s%%', $part);
$q->orWhereLike('description', $search);
}
}
});
}
return $search->take($limit)->get();
}
}

View File

@@ -1,40 +0,0 @@
<?php
/*
* JournalRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Journal;
use Illuminate\Support\Collection;
/**
* Interface JournalRepositoryInterface
*
* @deprecated
*/
interface JournalRepositoryInterface
{
/**
* Search in journal descriptions.
*/
public function searchJournalDescriptions(array $query, int $limit): Collection;
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* PiggyBankRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\PiggyBank;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
/**
* Class PiggyBankRepository
*
* @deprecated
*/
class PiggyBankRepository implements PiggyBankRepositoryInterface
{
use UserGroupTrait;
public function getPiggyBanks(): Collection
{
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_group_id', $this->userGroup->id)
->with(
[
'objectGroups',
]
)
->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*'])
;
}
}

View File

@@ -1,40 +0,0 @@
<?php
/*
* PiggyBankRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\PiggyBank;
use Illuminate\Support\Collection;
/**
* Interface PiggyBankRepositoryInterface
*
* @deprecated
*/
interface PiggyBankRepositoryInterface
{
/**
* Return all piggy banks.
*/
public function getPiggyBanks(): Collection;
}

View File

@@ -1,58 +0,0 @@
<?php
/*
* TagRepository.php
* Copyright (c) 2024 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Tag;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
/**
* Class TagRepository
*
* @deprecated
*/
class TagRepository implements TagRepositoryInterface
{
use UserGroupTrait;
public function searchTag(array $query, int $limit): Collection
{
$search = $this->userGroup->tags();
if (count($query) > 0) {
// split query on spaces just in case:
$search->where(function (EloquentBuilder $q) use ($query): void {
foreach ($query as $line) {
$parts = explode(' ', $line);
foreach ($parts as $part) {
$search = sprintf('%%%s%%', $part);
$q->orWhereLike('tag', $search);
}
}
});
}
return $search->take($limit)->get(['tags.*']);
}
}

View File

@@ -1,40 +0,0 @@
<?php
/*
* TagRepositoryInterface.php
* Copyright (c) 2024 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Tag;
use Illuminate\Support\Collection;
/**
* Interface TagRepositoryInterface
*
* @deprecated
*/
interface TagRepositoryInterface
{
/**
* Find one or more tags based on the query.
*/
public function searchTag(array $query, int $limit): Collection;
}

View File

@@ -28,12 +28,7 @@ use Illuminate\Contracts\Validation\ValidationRule;
class IsValidSortInstruction implements ValidationRule
{
private string $class;
public function __construct(string $class)
{
$this->class = $class;
}
public function __construct(private readonly string $class) {}
public function validate(string $attribute, mixed $value, Closure $fail): void
{

View File

@@ -221,13 +221,7 @@ class JournalUpdateService
private function hasFields(array $fields): bool
{
foreach ($fields as $field) {
if (array_key_exists($field, $this->data)) {
return true;
}
}
return false;
return array_any($fields, fn ($field) => array_key_exists($field, $this->data));
}
private function getOriginalSourceAccount(): Account

View File

@@ -29,11 +29,12 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Singleton\PreferencesSingleton;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use NumberFormatter;
use FireflyIII\Support\Facades\Steam;
/**
* Class Amount.
@@ -85,7 +86,7 @@ class Amount
public function formatByCurrencyId(int $currencyId, string $amount, ?bool $coloured = null): string
{
$format = TransactionCurrency::find($currencyId);
$format = $this->getTransactionCurrencyById($currencyId);
return $this->formatFlat($format->symbol, $format->decimal_places, $amount, $coloured);
}
@@ -115,6 +116,50 @@ class Amount
return (string)$amount;
}
public function getTransactionCurrencyById(int $currencyId): TransactionCurrency
{
$instance = PreferencesSingleton::getInstance();
$key = sprintf('transaction_currency_%d', $currencyId);
/** @var null|TransactionCurrency $pref */
$pref = $instance->getPreference($key);
if (null !== $pref) {
return $pref;
}
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
$message = sprintf('Could not find a transaction currency with ID #%d', $currencyId);
Log::error($message);
throw new FireflyException($message);
}
$instance->setPreference($key, $currency);
return $currency;
}
public function getTransactionCurrencyByCode(string $code): TransactionCurrency
{
$instance = PreferencesSingleton::getInstance();
$key = sprintf('transaction_currency_%s', $code);
/** @var null|TransactionCurrency $pref */
$pref = $instance->getPreference($key);
if (null !== $pref) {
return $pref;
}
$currency = TransactionCurrency::whereCode($code)->first();
if (null === $currency) {
$message = sprintf('Could not find a transaction currency with code "%s"', $code);
Log::error($message);
throw new FireflyException($message);
}
$instance->setPreference($key, $currency);
return $currency;
}
public function convertToPrimary(?User $user = null): bool
{
$instance = PreferencesSingleton::getInstance();

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Support;
use Carbon\Carbon;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
@@ -61,7 +61,7 @@ class Balance
foreach ($result as $entry) {
$accountId = (int) $entry->account_id;
$currencyId = (int) $entry->transaction_currency_id;
$currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$currencies[$currencyId] ??= Amount::getTransactionCurrencyById($currencyId);
$return[$accountId] ??= [];
if (array_key_exists($currencyId, $return[$accountId])) {
continue;

View File

@@ -23,7 +23,9 @@ declare(strict_types=1);
namespace FireflyIII\Support\Binder;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Routing\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -38,10 +40,13 @@ class CurrencyCode implements BinderInterface
public static function routeBinder(string $value, Route $route): TransactionCurrency
{
if (auth()->check()) {
$currency = TransactionCurrency::where('code', trim($value))->first();
if (null !== $currency) {
return $currency;
try {
$currency = Amount::getTransactionCurrencyByCode(trim($value));
} catch (FireflyException) {
throw new NotFoundHttpException();
}
return $currency;
}
throw new NotFoundHttpException();

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\Form;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Support\MessageBag;
use Throwable;
@@ -63,7 +62,7 @@ trait FormSupport
}
$name = str_replace('[]', '', $name);
return (string) trans('form.'.$name);
return (string)trans('form.'.$name);
}
/**
@@ -76,7 +75,7 @@ trait FormSupport
$options['class'] = 'form-control';
$options['id'] = 'ffInput_'.$name;
$options['autocomplete'] = 'off';
$options['placeholder'] = ucfirst((string) $label);
$options['placeholder'] = ucfirst((string)$label);
return $options;
}
@@ -146,15 +145,6 @@ trait FormSupport
protected function getDate(): Carbon
{
/** @var Carbon $date */
$date = null;
try {
$date = today(config('app.timezone'));
} catch (InvalidDateException $e) { // @phpstan-ignore-line
app('log')->error($e->getMessage());
}
return $date;
return today(config('app.timezone'));
}
}

View File

@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Navigation;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Collection;
@@ -184,7 +185,7 @@ class AccountBalanceGrouped
if (array_key_exists($currencyId, $this->currencies)) {
return $this->currencies[$currencyId];
}
$this->currencies[$currencyId] = TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = Amount::getTransactionCurrencyById($currencyId);
return $this->currencies[$currencyId];
}

View File

@@ -43,7 +43,7 @@ trait CleansChartData
$return = [];
/**
* @var mixed $index
* @var int $index
* @var array $array
*/
foreach ($data as $index => $array) {

View File

@@ -30,6 +30,7 @@ use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
@@ -264,11 +265,8 @@ class ExchangeRateConverter
if ($cache->has()) {
return (int) $cache->get();
}
$euro = TransactionCurrency::whereCode('EUR')->first();
$euro = Amount::getTransactionCurrencyByCode('EUR');
++$this->queryCount;
if (null === $euro) {
throw new FireflyException('Cannot find EUR in system, cannot do currency conversion.');
}
$cache->store($euro->id);
return $euro->id;

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Http\Api;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Facades\Log;
class SummaryBalanceGrouped
@@ -110,7 +111,7 @@ class SummaryBalanceGrouped
// transaction info:
$currencyId = (int) $journal['currency_id'];
$amount = bcmul((string) $journal['amount'], $multiplier);
$currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$currency = $this->currencies[$currencyId] ?? Amount::getTransactionCurrencyById($currencyId);
$this->currencies[$currencyId] = $currency;
$pcAmount = $converter->convert($currency, $this->default, $journal['date'], $amount);
if ((int) $journal['foreign_currency_id'] === $this->default->id) {

View File

@@ -38,8 +38,8 @@ use Illuminate\Support\Facades\Log;
*/
trait ValidatesUserGroupTrait
{
protected ?UserGroup $userGroup = null;
protected ?User $user = null;
protected UserGroup $userGroup;
protected User $user;
/**
* An "undocumented" filter

View File

@@ -60,7 +60,7 @@ class AccountEnrichment implements EnrichmentInterface
private array $currencies = [];
private array $locations = [];
private array $meta = [];
private TransactionCurrency $primaryCurrency;
private readonly TransactionCurrency $primaryCurrency;
private array $notes = [];
private array $openingBalances = [];
private User $user;
@@ -69,7 +69,7 @@ class AccountEnrichment implements EnrichmentInterface
private ?Carbon $date = null;
private ?Carbon $start = null;
private ?Carbon $end = null;
private bool $convertToPrimary;
private readonly bool $convertToPrimary;
private array $balances = [];
private array $startBalances = [];
private array $endBalances = [];
@@ -365,7 +365,7 @@ class AccountEnrichment implements EnrichmentInterface
private function collectBalances(): void
{
$this->balances = Steam::accountsBalancesOptimized($this->collection, $this->getDate(), $this->primaryCurrency, $this->convertToPrimary);
if (null !== $this->start && null !== $this->end) {
if ($this->start instanceof Carbon && $this->end instanceof Carbon) {
$this->startBalances = Steam::accountsBalancesOptimized($this->collection, $this->start, $this->primaryCurrency, $this->convertToPrimary);
$this->endBalances = Steam::accountsBalancesOptimized($this->collection, $this->end, $this->primaryCurrency, $this->convertToPrimary);
}
@@ -395,7 +395,7 @@ class AccountEnrichment implements EnrichmentInterface
public function setDate(?Carbon $date): void
{
if (null !== $date) {
if ($date instanceof Carbon) {
$date->endOfDay();
Log::debug(sprintf('Date is now %s', $date->toW3cString()));
}
@@ -404,7 +404,7 @@ class AccountEnrichment implements EnrichmentInterface
public function getDate(): Carbon
{
if (null === $this->date) {
if (!$this->date instanceof Carbon) {
return now();
}
@@ -423,7 +423,7 @@ class AccountEnrichment implements EnrichmentInterface
private function getBalanceDifference(int $id, TransactionCurrency $currency): ?string
{
if (null === $this->start || null === $this->end) {
if (!$this->start instanceof Carbon || !$this->end instanceof Carbon) {
return null;
}
$startBalance = $this->startBalances[$id] ?? [];
@@ -458,9 +458,7 @@ class AccountEnrichment implements EnrichmentInterface
case 'current_balance':
case 'pc_current_balance':
$this->collection = $this->collection->sortBy(static function (Account $account) use ($parameter) {
return $account->meta['balances'][$parameter[0]] ?? '0';
}, SORT_NUMERIC, 'desc' === $parameter[1]);
$this->collection = $this->collection->sortBy(static fn (Account $account) => $account->meta['balances'][$parameter[0]] ?? '0', SORT_NUMERIC, 'desc' === $parameter[1]);
break;
}

View File

@@ -42,7 +42,7 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
{
private User $user; // @phpstan-ignore-line
private UserGroup $userGroup; // @phpstan-ignore-line
private bool $convertToPrimary;
private readonly bool $convertToPrimary;
private array $ids = [];
private array $currencyIds = [];
private array $currencies = [];

View File

@@ -161,7 +161,7 @@ class BudgetEnrichment implements EnrichmentInterface
private function collectExpenses(): void
{
if (null !== $this->start && null !== $this->end) {
if ($this->start instanceof Carbon && $this->end instanceof Carbon) {
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
$opsRepository->setUser($this->user);

View File

@@ -53,7 +53,7 @@ class BudgetLimitEnrichment implements EnrichmentInterface
private array $currencyIds = [];
private array $currencies = [];
private bool $convertToPrimary = true;
private TransactionCurrency $primaryCurrency;
private readonly TransactionCurrency $primaryCurrency;
public function __construct()
{
@@ -181,27 +181,21 @@ class BudgetLimitEnrichment implements EnrichmentInterface
private function stringifyIds(): void
{
$this->expenses = array_map(function ($first) {
return array_map(function ($second) {
$second['currency_id'] = (string)($second['currency_id'] ?? 0);
$this->expenses = array_map(fn ($first) => array_map(function ($second) {
$second['currency_id'] = (string)($second['currency_id'] ?? 0);
return $second;
}, $first);
}, $this->expenses);
return $second;
}, $first), $this->expenses);
$this->pcExpenses = array_map(function ($first) {
return array_map(function ($second) {
$second['currency_id'] = (string)($second['currency_id'] ?? 0);
$this->pcExpenses = array_map(fn ($first) => array_map(function ($second) {
$second['currency_id'] = (string)($second['currency_id'] ?? 0);
return $second;
}, $first);
}, $this->expenses);
return $second;
}, $first), $this->expenses);
}
private function filterToBudget(array $expenses, int $budget): array
{
return array_filter($expenses, function (array $item) use ($budget) {
return (int)$item['budget_id'] === $budget;
});
return array_filter($expenses, fn (array $item) => (int)$item['budget_id'] === $budget);
}
}

View File

@@ -53,7 +53,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
// private array $accountCurrencies = [];
private array $notes = [];
private array $mappedObjects = [];
private TransactionCurrency $primaryCurrency;
private readonly TransactionCurrency $primaryCurrency;
private array $amounts = [];
private array $accounts = [];
private array $objectGroups = [];
@@ -142,7 +142,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
$accountId = (int)$item->account_id;
$currencyId = (int)$item->data;
if (!array_key_exists($currencyId, $this->currencies)) {
$this->currencies[$currencyId] = TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = Amount::getTransactionCurrencyById($currencyId);
}
// $this->accountCurrencies[$accountId] = $this->currencies[$currencyId];
}
@@ -271,7 +271,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
*/
private function getSuggestedMonthlyAmount(?Carbon $startDate, ?Carbon $targetDate, ?string $targetAmount, string $currentAmount): string
{
if (null === $targetAmount || null === $targetDate || null === $startDate) {
if (null === $targetAmount || !$targetDate instanceof Carbon || !$startDate instanceof Carbon) {
return '0';
}
$savePerMonth = '0';

View File

@@ -27,7 +27,6 @@ namespace FireflyIII\Support\JsonApi\Enrichments;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Facades\Amount;
@@ -121,7 +120,7 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
$accountId = (int)$item->account_id;
$currencyId = (int)$item->data;
if (!array_key_exists($currencyId, $this->currencies)) {
$this->currencies[$currencyId] = TransactionCurrency::find($currencyId);
$this->currencies[$currencyId] = Amount::getTransactionCurrencyById($currencyId);
}
$this->accountCurrencies[$accountId] = $this->currencies[$currencyId];
}

View File

@@ -49,7 +49,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
private User $user;
private UserGroup $userGroup; // @phpstan-ignore-line
private Collection $collection;
private bool $convertToPrimary;
private readonly bool $convertToPrimary;
private ?Carbon $start = null;
private ?Carbon $end = null;
private array $subscriptionIds = [];
@@ -58,7 +58,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
private array $paidDates = [];
private array $notes = [];
private array $payDates = [];
private TransactionCurrency $primaryCurrency;
private readonly TransactionCurrency $primaryCurrency;
private BillDateCalculator $calculator;
public function __construct()
@@ -210,7 +210,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
{
$this->paidDates = [];
Log::debug('Now in collectPaidDates for bills');
if (null === $this->start || null === $this->end) {
if (!$this->start instanceof Carbon || !$this->end instanceof Carbon) {
Log::debug('Parameters are NULL, set empty array');
return;
@@ -274,9 +274,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
// At this point the "next match" is exactly after the last time the bill was paid.
$result = [];
$filtered = $set->filter(function (TransactionJournal $journal) use ($subscription) {
return (int)$journal->bill_id === (int)$subscription->id;
});
$filtered = $set->filter(fn (TransactionJournal $journal) => (int)$journal->bill_id === (int)$subscription->id);
foreach ($filtered as $entry) {
$array = [
'transaction_group_id' => (string)$entry->transaction_group_id,
@@ -321,7 +319,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
if ($this->convertToPrimary && null !== $entry->foreign_currency_id && (int)$entry->foreign_currency_id !== $this->primaryCurrency->id) {
// TODO this is very database intensive.
/** @var TransactionCurrency $foreignCurrency */
$foreignCurrency = TransactionCurrency::find($entry->foreign_currency_id);
$foreignCurrency = Amount::getTransactionCurrencyById($entry->foreign_currency_id);
$array['pc_foreign_amount'] = $converter->convert($foreignCurrency, $this->primaryCurrency, $entry->date, $entry->amount);
}
$result[] = $array;
@@ -346,9 +344,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
*/
protected function lastPaidDate(Bill $subscription, Collection $dates, Carbon $default): Carbon
{
$filtered = $dates->filter(function (TransactionJournal $journal) use ($subscription) {
return (int)$journal->bill_id === (int)$subscription->id;
});
$filtered = $dates->filter(fn (TransactionJournal $journal) => (int)$journal->bill_id === (int)$subscription->id);
Log::debug(sprintf('Filtered down from %d to %d entries for bill #%d.', $dates->count(), $filtered->count(), $subscription->id));
if (0 === $filtered->count()) {
return $default;
@@ -392,7 +388,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
private function collectPayDates(): void
{
if (null === $this->start || null === $this->end) {
if (!$this->start instanceof Carbon || !$this->end instanceof Carbon) {
Log::debug('Parameters are NULL, set empty array');
return;
@@ -440,8 +436,8 @@ class SubscriptionEnrichment implements EnrichmentInterface
// nullify again when it's outside the current view range.
if (
(null !== $this->start && $nemDate->lt($this->start))
|| (null !== $this->end && $nemDate->gt($this->end))
($this->start instanceof Carbon && $nemDate->lt($this->start))
|| ($this->end instanceof Carbon && $nemDate->gt($this->end))
) {
$nem = null;
$nemDate = null;
@@ -454,7 +450,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
private function getNextExpectedMatchDiff(?Carbon $nem, array $payDates): string
{
if (null === $nem) {
if (!$nem instanceof Carbon) {
return trans('firefly.not_expected_period');
}
$nemDiff = trans('firefly.not_expected_period');

View File

@@ -25,11 +25,12 @@ declare(strict_types=1);
namespace FireflyIII\Support\Models;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountBalance;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
@@ -102,7 +103,7 @@ class AccountBalanceCalculator
// before and after are easy:
$before = $balances[$entry->account_id][$entry->transaction_currency_id][0];
$after = bcadd($before, (string) $entry->amount);
$after = bcadd($before, (string)$entry->amount);
if (true === $entry->balance_dirty || $accounts->count() > 0) {
// update the transaction:
$entry->balance_before = $before;
@@ -144,7 +145,7 @@ class AccountBalanceCalculator
$query->where('transaction_journals.date', '<', $notBefore);
$first = $query->first(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount', 'transactions.balance_after']);
$balance = (string) ($first->balance_after ?? '0');
$balance = (string)($first->balance_after ?? '0');
Log::debug(sprintf('getLatestBalance: found balance: %s in transaction #%d', $balance, $first->id ?? 0));
return $balance;
@@ -170,9 +171,9 @@ class AccountBalanceCalculator
* @var array $balance
*/
foreach ($currencies as $currencyId => $balance) {
/** @var null|TransactionCurrency $currency */
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
try {
$currency = Amount::getTransactionCurrencyById($currencyId);
} catch (FireflyException) {
Log::error(sprintf('Could not find currency #%d, will not save account balance.', $currencyId));
continue;

View File

@@ -78,7 +78,7 @@ class ParseDateString
*/
public function parseDate(string $date): Carbon
{
app('log')->debug(sprintf('parseDate("%s")', $date));
Log::debug(sprintf('parseDate("%s")', $date));
$date = strtolower($date);
// parse keywords:
if (in_array($date, $this->keywords, true)) {
@@ -107,7 +107,7 @@ class ParseDateString
// maybe a date range
if (10 === strlen($date) && (str_contains($date, 'xx') || str_contains($date, 'xxxx'))) {
app('log')->debug(sprintf('[c] Detected a date range ("%s"), return a fake date.', $date));
Log::debug(sprintf('[c] Detected a date range ("%s"), return a fake date.', $date));
// very lazy way to parse the date without parsing it, because this specific function
// cant handle date ranges.
@@ -158,7 +158,7 @@ class ParseDateString
protected function parseRelativeDate(string $date): Carbon
{
app('log')->debug(sprintf('Now in parseRelativeDate("%s")', $date));
Log::debug(sprintf('Now in parseRelativeDate("%s")', $date));
$parts = explode(' ', $date);
$today = today(config('app.timezone'))->startOfDay();
$functions = [
@@ -179,14 +179,14 @@ class ParseDateString
];
foreach ($parts as $part) {
app('log')->debug(sprintf('Now parsing part "%s"', $part));
Log::debug(sprintf('Now parsing part "%s"', $part));
$part = trim($part);
// verify if correct
$pattern = '/[+-]\d+[wqmdy]/';
$result = preg_match($pattern, $part);
if (0 === $result || false === $result) {
app('log')->error(sprintf('Part "%s" does not match regular expression. Will be skipped.', $part));
if (0 === $result) {
Log::error(sprintf('Part "%s" does not match regular expression. Will be skipped.', $part));
continue;
}
@@ -194,14 +194,14 @@ class ParseDateString
$period = $part[strlen($part) - 1];
$number = (int) substr($part, 1, -1);
if (!array_key_exists($period, $functions[$direction])) {
app('log')->error(sprintf('No method for direction %d and period "%s".', $direction, $period));
Log::error(sprintf('No method for direction %d and period "%s".', $direction, $period));
continue;
}
$func = $functions[$direction][$period];
app('log')->debug(sprintf('Will now do %s(%d) on %s', $func, $number, $today->format('Y-m-d')));
Log::debug(sprintf('Will now do %s(%d) on %s', $func, $number, $today->format('Y-m-d')));
$today->{$func}($number); // @phpstan-ignore-line
app('log')->debug(sprintf('Resulting date is %s', $today->format('Y-m-d')));
Log::debug(sprintf('Resulting date is %s', $today->format('Y-m-d')));
}
return $today;
@@ -260,11 +260,11 @@ class ParseDateString
$pattern = '/^xxxx-xx-(0[1-9]|[12]\d|3[01])$/';
$result = preg_match($pattern, $date);
if (0 !== $result) {
app('log')->debug(sprintf('"%s" is a day range.', $date));
Log::debug(sprintf('"%s" is a day range.', $date));
return true;
}
app('log')->debug(sprintf('"%s" is not a day range.', $date));
Log::debug(sprintf('"%s" is not a day range.', $date));
return false;
}
@@ -287,11 +287,11 @@ class ParseDateString
$pattern = '/^xxxx-(0[1-9]|1[012])-xx$/';
$result = preg_match($pattern, $date);
if (0 !== $result) {
app('log')->debug(sprintf('"%s" is a month range.', $date));
Log::debug(sprintf('"%s" is a month range.', $date));
return true;
}
app('log')->debug(sprintf('"%s" is not a month range.', $date));
Log::debug(sprintf('"%s" is not a month range.', $date));
return false;
}
@@ -301,7 +301,7 @@ class ParseDateString
*/
protected function parseMonthRange(string $date): array
{
app('log')->debug(sprintf('parseMonthRange: Parsed "%s".', $date));
Log::debug(sprintf('parseMonthRange: Parsed "%s".', $date));
$parts = explode('-', $date);
return [
@@ -315,11 +315,11 @@ class ParseDateString
$pattern = '/^(19|20)\d\d-xx-xx$/';
$result = preg_match($pattern, $date);
if (0 !== $result) {
app('log')->debug(sprintf('"%s" is a year range.', $date));
Log::debug(sprintf('"%s" is a year range.', $date));
return true;
}
app('log')->debug(sprintf('"%s" is not a year range.', $date));
Log::debug(sprintf('"%s" is not a year range.', $date));
return false;
}
@@ -329,7 +329,7 @@ class ParseDateString
*/
protected function parseYearRange(string $date): array
{
app('log')->debug(sprintf('parseYearRange: Parsed "%s"', $date));
Log::debug(sprintf('parseYearRange: Parsed "%s"', $date));
$parts = explode('-', $date);
return [
@@ -343,11 +343,11 @@ class ParseDateString
$pattern = '/^xxxx-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01])$/';
$result = preg_match($pattern, $date);
if (0 !== $result) {
app('log')->debug(sprintf('"%s" is a month/day range.', $date));
Log::debug(sprintf('"%s" is a month/day range.', $date));
return true;
}
app('log')->debug(sprintf('"%s" is not a month/day range.', $date));
Log::debug(sprintf('"%s" is not a month/day range.', $date));
return false;
}
@@ -357,7 +357,7 @@ class ParseDateString
*/
private function parseMonthDayRange(string $date): array
{
app('log')->debug(sprintf('parseMonthDayRange: Parsed "%s".', $date));
Log::debug(sprintf('parseMonthDayRange: Parsed "%s".', $date));
$parts = explode('-', $date);
return [
@@ -372,11 +372,11 @@ class ParseDateString
$pattern = '/^(19|20)\d\d-xx-(0[1-9]|[12]\d|3[01])$/';
$result = preg_match($pattern, $date);
if (0 !== $result) {
app('log')->debug(sprintf('"%s" is a day/year range.', $date));
Log::debug(sprintf('"%s" is a day/year range.', $date));
return true;
}
app('log')->debug(sprintf('"%s" is not a day/year range.', $date));
Log::debug(sprintf('"%s" is not a day/year range.', $date));
return false;
}
@@ -386,7 +386,7 @@ class ParseDateString
*/
private function parseDayYearRange(string $date): array
{
app('log')->debug(sprintf('parseDayYearRange: Parsed "%s".', $date));
Log::debug(sprintf('parseDayYearRange: Parsed "%s".', $date));
$parts = explode('-', $date);
return [
@@ -401,11 +401,11 @@ class ParseDateString
$pattern = '/^(19|20)\d\d-(0[1-9]|1[012])-xx$/';
$result = preg_match($pattern, $date);
if (0 !== $result) {
app('log')->debug(sprintf('"%s" is a month/year range.', $date));
Log::debug(sprintf('"%s" is a month/year range.', $date));
return true;
}
app('log')->debug(sprintf('"%s" is not a month/year range.', $date));
Log::debug(sprintf('"%s" is not a month/year range.', $date));
return false;
}
@@ -415,7 +415,7 @@ class ParseDateString
*/
protected function parseMonthYearRange(string $date): array
{
app('log')->debug(sprintf('parseMonthYearRange: Parsed "%s".', $date));
Log::debug(sprintf('parseMonthYearRange: Parsed "%s".', $date));
$parts = explode('-', $date);
return [

View File

@@ -72,7 +72,7 @@ trait UserGroupTrait
return;
}
$class = null === $user ? 'NULL' : $user::class;
$class = $user instanceof Authenticatable ? $user::class : 'NULL';
throw new FireflyException(sprintf('Object is %s, not User.', $class));
}

View File

@@ -103,6 +103,9 @@ trait ConvertsDataTypes
{
// assume this all works, because the validator would have caught any errors.
$parameter = (string)request()->query->get($field);
if ('' === $parameter) {
return [];
}
$parts = explode(',', $parameter);
$sortParameters = [];
foreach ($parts as $part) {

View File

@@ -1,83 +0,0 @@
<?php
/*
* GetFilterInstructions.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Request;
use FireflyIII\Exceptions\FireflyException;
trait GetFilterInstructions
{
private const string INVALID_FILTER = '%INVALID_JAMES_%';
/**
* @throws FireflyException
*/
final public function getFilterInstructions(string $key): array
{
$config = config(sprintf('firefly.filters.allowed.%s', $key));
$allowed = array_keys($config);
$set = $this->get('filters', []);
$result = [];
if (0 === count($set)) {
return [];
}
foreach ($set as $info) {
$column = $info['column'] ?? 'NOPE';
$filterValue = (string) ($info['filter'] ?? self::INVALID_FILTER);
if (false === in_array($column, $allowed, true)) {
// skip invalid column
continue;
}
$filterType = $config[$column] ?? false;
switch ($filterType) {
default:
throw new FireflyException(sprintf('Do not support filter type "%s"', $filterType));
case 'boolean':
$filterValue = $this->booleanInstruction($filterValue);
break;
case 'string':
break;
}
$result[$column] = $filterValue;
}
return $result;
}
public function booleanInstruction(string $filterValue): ?bool
{
if ('true' === $filterValue) {
return true;
}
if ('false' === $filterValue) {
return false;
}
return null;
}
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* GetSortInstructions.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Request;
trait GetSortInstructions
{
final public function getSortInstructions(string $key): array
{
$allowed = config(sprintf('firefly.sorting.allowed.%s', $key));
$set = $this->get('sorting', []);
$result = [];
if (0 === count($set)) {
return [];
}
foreach ($set as $info) {
$column = $info['column'] ?? 'NOPE';
$direction = $info['direction'] ?? 'NOPE';
if ('asc' !== $direction && 'desc' !== $direction) {
// skip invalid direction
continue;
}
if (false === in_array($column, $allowed, true)) {
// skip invalid column
continue;
}
$result[$column] = $direction;
}
return $result;
}
}

View File

@@ -25,9 +25,9 @@ declare(strict_types=1);
namespace FireflyIII\Support\Request;
use Illuminate\Validation\Validator;
use FireflyIII\Enums\WebhookTrigger;
use FireflyIII\Models\Webhook;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Support\Facades\Log;
trait ValidatesWebhooks
@@ -37,7 +37,7 @@ trait ValidatesWebhooks
$validator->after(
function (Validator $validator): void {
Log::debug('Validating webhook');
if ($validator->failed()) {
if (count($validator->failed()) > 0) {
return;
}
$data = $validator->getData();

View File

@@ -285,7 +285,7 @@ class Steam
$sumOfDay = $this->floatalize($sumOfDay);
// find currency of this entry, does not have to exist.
$currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id);
$currencies[$entry->transaction_currency_id] ??= Amount::getTransactionCurrencyById($entry->transaction_currency_id);
// make sure this $entry has its own $entryCurrency
/** @var TransactionCurrency $entryCurrency */
@@ -348,9 +348,7 @@ class Steam
$currency = $currencies[$account->id];
// second array
$accountSum = array_filter($arrayOfSums, function ($entry) use ($account) {
return $entry['account_id'] === $account->id;
});
$accountSum = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id);
if (0 === count($accountSum)) {
$result[$account->id] = $return;
@@ -502,7 +500,7 @@ class Steam
return null;
}
return TransactionCurrency::find((int)$result->data);
return Amount::getTransactionCurrencyById((int)$result->data);
}
private function groupAndSumTransactions(array $array, string $group, string $field): array
@@ -524,8 +522,10 @@ class Steam
$singleton = PreferencesSingleton::getInstance();
foreach ($others as $key => $amount) {
$preference = $singleton->getPreference($key);
$currency = $preference ?? TransactionCurrency::where('code', $key)->first();
if (null === $currency) {
try {
$currency = $preference ?? Amount::getTransactionCurrencyByCode($key);
} catch (FireflyException) {
continue;
}
if (null === $preference) {

View File

@@ -162,9 +162,9 @@ class AmountFormat extends AbstractExtension
static function (string $amount, string $code, ?bool $coloured = null): string {
$coloured ??= true;
/** @var null|TransactionCurrency $currency */
$currency = TransactionCurrency::whereCode($code)->first();
if (null === $currency) {
try {
$currency = Amount::getTransactionCurrencyByCode($code);
} catch (FireflyException) {
Log::error(sprintf('Could not find currency with code "%s". Fallback to primary currency.', $code));
$currency = Amount::getPrimaryCurrency();
Log::error(sprintf('Fallback currency is "%s".', $currency->code));

Some files were not shown because too many files have changed in this diff Show More