Merge branch 'develop'

This commit is contained in:
github-actions 2024-12-30 16:07:29 +00:00
commit 31722477d4
832 changed files with 19816 additions and 14645 deletions

View File

@ -29,7 +29,7 @@ $paths = [
$current . '/../../database', $current . '/../../database',
$current . '/../../routes', $current . '/../../routes',
$current . '/../../tests', $current . '/../../tests',
$current . '/../../resources/lang', $current . '/../../resources/lang/en_US',
]; ];
$finder = PhpCsFixer\Finder::create() $finder = PhpCsFixer\Finder::create()

View File

@ -97,13 +97,13 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "3.x-dev"
},
"phpstan": { "phpstan": {
"includes": [ "includes": [
"extension.neon" "extension.neon"
] ]
},
"branch-alias": {
"dev-main": "3.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -406,16 +406,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.65.0", "version": "v3.66.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f" "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6",
"reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f", "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -441,7 +441,7 @@
"symfony/polyfill-mbstring": "^1.28", "symfony/polyfill-mbstring": "^1.28",
"symfony/polyfill-php80": "^1.28", "symfony/polyfill-php80": "^1.28",
"symfony/polyfill-php81": "^1.28", "symfony/polyfill-php81": "^1.28",
"symfony/process": "^5.4 || ^6.0 || ^7.0", "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2",
"symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0"
}, },
"require-dev": { "require-dev": {
@ -497,7 +497,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.65.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0"
}, },
"funding": [ "funding": [
{ {
@ -505,7 +505,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-11-25T00:39:24+00:00" "time": "2024-12-29T13:46:23+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@ -1369,12 +1369,12 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
} }
}, },
"autoload": { "autoload": {
@ -1517,12 +1517,12 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
} }
}, },
"autoload": { "autoload": {
@ -2246,16 +2246,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v7.2.0", "version": "v7.1.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892",
"reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2287,7 +2287,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v7.2.0" "source": "https://github.com/symfony/process/tree/v7.1.8"
}, },
"funding": [ "funding": [
{ {
@ -2303,7 +2303,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-06T14:24:19+00:00" "time": "2024-11-06T14:23:19+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
@ -2329,12 +2329,12 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
} }
}, },
"autoload": { "autoload": {

View File

@ -26,8 +26,7 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd $SCRIPT_DIR/php-cs-fixer cd $SCRIPT_DIR/php-cs-fixer
composer update --quiet composer update --quiet
rm -f .php-cs-fixer.cache rm -f .php-cs-fixer.cache
PHP_CS_FIXER_IGNORE_ENV=true PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix \
./vendor/bin/php-cs-fixer fix \
--config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \ --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \
--format=txt \ --format=txt \
--allow-risky=yes --allow-risky=yes

View File

@ -19,7 +19,7 @@ jobs:
- name: Setup PHP with Xdebug - name: Setup PHP with Xdebug
uses: shivammathur/setup-php@v2 uses: shivammathur/setup-php@v2
with: with:
php-version: '8.3' php-version: '8.4'
coverage: xdebug coverage: xdebug
extensions: >- extensions: >-
bcmath bcmath

View File

@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution. Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2024 ## 2024
- TasneemTantawy
- Antônio Franco - Antônio Franco
- yparitcher - yparitcher
- Jhon Pedroza - Jhon Pedroza

View File

@ -26,10 +26,11 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest; use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@ -61,7 +62,7 @@ class AccountController extends Controller
return $next($request); return $next($request);
} }
); );
$this->balanceTypes = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]; $this->balanceTypes = [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
} }
/** /**
@ -78,35 +79,35 @@ class AccountController extends Controller
$query = $data['query']; $query = $data['query'];
$date = $data['date'] ?? today(config('app.timezone')); $date = $data['date'] ?? today(config('app.timezone'));
$return = []; $return = [];
$result = $this->repository->searchAccount((string)$query, $types, $this->parameters->get('limit')); $result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
// TODO this code is duplicated in the V2 Autocomplete controller, which means this code is due to be deprecated.
$defaultCurrency = app('amount')->getDefaultCurrency();
/** @var Account $account */ /** @var Account $account */
foreach ($result as $account) { foreach ($result as $account) {
$nameWithBalance = $account->name; $nameWithBalance = $account->name;
$currency = $this->repository->getAccountCurrency($account) ?? $defaultCurrency; $currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) { if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = app('steam')->balance($account, $date); $balance = Steam::finalAccountBalance($account, $date);
$key = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$useCurrency = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? $this->defaultCurrency : $currency;
$amount = $balance[$key] ?? '0';
$nameWithBalance = sprintf( $nameWithBalance = sprintf(
'%s (%s)', '%s (%s)',
$account->name, $account->name,
app('amount')->formatAnything($currency, $balance, false) app('amount')->formatAnything($useCurrency, $amount, false)
); );
} }
$return[] = [ $return[] = [
'id' => (string)$account->id, 'id' => (string) $account->id,
'name' => $account->name, 'name' => $account->name,
'name_with_balance' => $nameWithBalance, 'name_with_balance' => $nameWithBalance,
'type' => $account->accountType->type, 'type' => $account->accountType->type,
'currency_id' => (string)$currency->id, 'currency_id' => (string) $useCurrency->id,
'currency_name' => $currency->name, 'currency_name' => $useCurrency->name,
'currency_code' => $currency->code, 'currency_code' => $useCurrency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $useCurrency->decimal_places,
]; ];
} }
@ -114,9 +115,9 @@ class AccountController extends Controller
usort( usort(
$return, $return,
static function (array $left, array $right) { static function (array $left, array $right) {
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE]; $order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
$posA = (int)array_search($left['type'], $order, true); $posA = (int) array_search($left['type'], $order, true);
$posB = (int)array_search($right['type'], $order, true); $posB = (int) array_search($right['type'], $order, true);
return $posA - $posB; return $posA - $posB;
} }

View File

@ -67,7 +67,7 @@ class BillController extends Controller
$filtered = $result->map( $filtered = $result->map(
static function (Bill $item) { static function (Bill $item) {
return [ return [
'id' => (string)$item->id, 'id' => (string) $item->id,
'name' => $item->name, 'name' => $item->name,
'active' => $item->active, 'active' => $item->active,
]; ];

View File

@ -67,7 +67,7 @@ class BudgetController extends Controller
$filtered = $result->map( $filtered = $result->map(
static function (Budget $item) { static function (Budget $item) {
return [ return [
'id' => (string)$item->id, 'id' => (string) $item->id,
'name' => $item->name, 'name' => $item->name,
]; ];
} }

View File

@ -67,7 +67,7 @@ class CategoryController extends Controller
$filtered = $result->map( $filtered = $result->map(
static function (Category $item) { static function (Category $item) {
return [ return [
'id' => (string)$item->id, 'id' => (string) $item->id,
'name' => $item->name, 'name' => $item->name,
]; ];
} }

View File

@ -69,7 +69,7 @@ class CurrencyController extends Controller
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($collection as $currency) { foreach ($collection as $currency) {
$result[] = [ $result[] = [
'id' => (string)$currency->id, 'id' => (string) $currency->id,
'name' => $currency->name, 'name' => $currency->name,
'code' => $currency->code, 'code' => $currency->code,
'symbol' => $currency->symbol, 'symbol' => $currency->symbol,
@ -95,7 +95,7 @@ class CurrencyController extends Controller
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($collection as $currency) { foreach ($collection as $currency) {
$result[] = [ $result[] = [
'id' => (string)$currency->id, 'id' => (string) $currency->id,
'name' => sprintf('%s (%s)', $currency->name, $currency->code), 'name' => sprintf('%s (%s)', $currency->name, $currency->code),
'code' => $currency->code, 'code' => $currency->code,
'symbol' => $currency->symbol, 'symbol' => $currency->symbol,

View File

@ -69,7 +69,7 @@ class ObjectGroupController extends Controller
/** @var ObjectGroup $objectGroup */ /** @var ObjectGroup $objectGroup */
foreach ($result as $objectGroup) { foreach ($result as $objectGroup) {
$return[] = [ $return[] = [
'id' => (string)$objectGroup->id, 'id' => (string) $objectGroup->id,
'name' => $objectGroup->title, 'name' => $objectGroup->title,
'title' => $objectGroup->title, 'title' => $objectGroup->title,
]; ];

View File

@ -68,22 +68,21 @@ class PiggyBankController extends Controller
{ {
$data = $request->getData(); $data = $request->getData();
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit')); $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
$defaultCurrency = app('amount')->getDefaultCurrency();
$response = []; $response = [];
/** @var PiggyBank $piggy */ /** @var PiggyBank $piggy */
foreach ($piggies as $piggy) { foreach ($piggies as $piggy) {
$currency = $this->accountRepository->getAccountCurrency($piggy->account) ?? $defaultCurrency; $currency = $piggy->transactionCurrency;
$objectGroup = $piggy->objectGroups()->first(); $objectGroup = $piggy->objectGroups()->first();
$response[] = [ $response[] = [
'id' => (string)$piggy->id, 'id' => (string) $piggy->id,
'name' => $piggy->name, 'name' => $piggy->name,
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
'object_group_id' => null === $objectGroup ? null : (string)$objectGroup->id, 'object_group_id' => null === $objectGroup ? null : (string) $objectGroup->id,
'object_group_title' => $objectGroup?->title, 'object_group_title' => $objectGroup?->title,
]; ];
} }
@ -99,29 +98,28 @@ class PiggyBankController extends Controller
{ {
$data = $request->getData(); $data = $request->getData();
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit')); $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
$defaultCurrency = app('amount')->getDefaultCurrency();
$response = []; $response = [];
/** @var PiggyBank $piggy */ /** @var PiggyBank $piggy */
foreach ($piggies as $piggy) { foreach ($piggies as $piggy) {
$currency = $this->accountRepository->getAccountCurrency($piggy->account) ?? $defaultCurrency; $currency = $piggy->transactionCurrency;
$currentAmount = $this->piggyRepository->getRepetition($piggy)->currentamount ?? '0'; $currentAmount = $this->piggyRepository->getCurrentAmount($piggy);
$objectGroup = $piggy->objectGroups()->first(); $objectGroup = $piggy->objectGroups()->first();
$response[] = [ $response[] = [
'id' => (string)$piggy->id, 'id' => (string) $piggy->id,
'name' => $piggy->name, 'name' => $piggy->name,
'name_with_balance' => sprintf( 'name_with_balance' => sprintf(
'%s (%s / %s)', '%s (%s / %s)',
$piggy->name, $piggy->name,
app('amount')->formatAnything($currency, $currentAmount, false), app('amount')->formatAnything($currency, $currentAmount, false),
app('amount')->formatAnything($currency, $piggy->targetamount, false), app('amount')->formatAnything($currency, $piggy->target_amount, false),
), ),
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
'object_group_id' => null === $objectGroup ? null : (string)$objectGroup->id, 'object_group_id' => null === $objectGroup ? null : (string) $objectGroup->id,
'object_group_title' => $objectGroup?->title, 'object_group_title' => $objectGroup?->title,
]; ];
} }

View File

@ -67,7 +67,7 @@ class RecurrenceController extends Controller
/** @var Recurrence $recurrence */ /** @var Recurrence $recurrence */
foreach ($recurrences as $recurrence) { foreach ($recurrences as $recurrence) {
$response[] = [ $response[] = [
'id' => (string)$recurrence->id, 'id' => (string) $recurrence->id,
'name' => $recurrence->title, 'name' => $recurrence->title,
'description' => $recurrence->description, 'description' => $recurrence->description,
]; ];

View File

@ -66,7 +66,7 @@ class RuleController extends Controller
/** @var Rule $rule */ /** @var Rule $rule */
foreach ($rules as $rule) { foreach ($rules as $rule) {
$response[] = [ $response[] = [
'id' => (string)$rule->id, 'id' => (string) $rule->id,
'name' => $rule->title, 'name' => $rule->title,
'description' => $rule->description, 'description' => $rule->description,
]; ];

View File

@ -66,7 +66,7 @@ class RuleGroupController extends Controller
/** @var RuleGroup $group */ /** @var RuleGroup $group */
foreach ($groups as $group) { foreach ($groups as $group) {
$response[] = [ $response[] = [
'id' => (string)$group->id, 'id' => (string) $group->id,
'name' => $group->title, 'name' => $group->title,
'description' => $group->description, 'description' => $group->description,
]; ];

View File

@ -69,7 +69,7 @@ class TagController extends Controller
/** @var Tag $tag */ /** @var Tag $tag */
foreach ($result as $tag) { foreach ($result as $tag) {
$array[] = [ $array[] = [
'id' => (string)$tag->id, 'id' => (string) $tag->id,
'name' => $tag->tag, 'name' => $tag->tag,
'tag' => $tag->tag, 'tag' => $tag->tag,
]; ];

View File

@ -77,8 +77,8 @@ class TransactionController extends Controller
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($filtered as $journal) { foreach ($filtered as $journal) {
$array[] = [ $array[] = [
'id' => (string)$journal->id, 'id' => (string) $journal->id,
'transaction_group_id' => (string)$journal->transaction_group_id, 'transaction_group_id' => (string) $journal->transaction_group_id,
'name' => $journal->description, 'name' => $journal->description,
'description' => $journal->description, 'description' => $journal->description,
]; ];
@ -97,7 +97,7 @@ class TransactionController extends Controller
$result = new Collection(); $result = new Collection();
if (is_numeric($data['query'])) { if (is_numeric($data['query'])) {
// search for group, not journal. // search for group, not journal.
$firstResult = $this->groupRepository->find((int)$data['query']); $firstResult = $this->groupRepository->find((int) $data['query']);
if (null !== $firstResult) { if (null !== $firstResult) {
// group may contain multiple journals, each a result: // group may contain multiple journals, each a result:
foreach ($firstResult->transactionJournals as $journal) { foreach ($firstResult->transactionJournals as $journal) {
@ -115,8 +115,8 @@ class TransactionController extends Controller
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($result as $journal) { foreach ($result as $journal) {
$array[] = [ $array[] = [
'id' => (string)$journal->id, 'id' => (string) $journal->id,
'transaction_group_id' => (string)$journal->transaction_group_id, 'transaction_group_id' => (string) $journal->transaction_group_id,
'name' => sprintf('#%d: %s', $journal->transaction_group_id, $journal->description), 'name' => sprintf('#%d: %s', $journal->transaction_group_id, $journal->description),
'description' => sprintf('#%d: %s', $journal->transaction_group_id, $journal->description), 'description' => sprintf('#%d: %s', $journal->transaction_group_id, $journal->description),
]; ];

View File

@ -66,7 +66,7 @@ class TransactionTypeController extends Controller
foreach ($types as $type) { foreach ($types as $type) {
// different key for consistency. // different key for consistency.
$array[] = [ $array[] = [
'id' => (string)$type->id, 'id' => (string) $type->id,
'name' => $type->type, 'name' => $type->type,
'type' => $type->type, 'type' => $type->type,
]; ];

View File

@ -27,9 +27,9 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest; use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\ApiSupport; use FireflyIII\Support\Http\Api\ApiSupport;
@ -81,11 +81,10 @@ class AccountController extends Controller
$end = $dates['end']; $end = $dates['end'];
// user's preferences // user's preferences
$defaultSet = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray(); $defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
/** @var Preference $frontpage */ /** @var Preference $frontpage */
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet); $frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
$default = app('amount')->getDefaultCurrency();
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) { if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet; $frontpage->data = $defaultSet;
@ -98,13 +97,11 @@ class AccountController extends Controller
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account); $currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
if (null === $currency) { $field = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$currency = $default;
}
$currentSet = [ $currentSet = [
'label' => $account->name, 'label' => $account->name,
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@ -116,13 +113,12 @@ class AccountController extends Controller
]; ];
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated. // TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
$currentStart = clone $start; $currentStart = clone $start;
$range = app('steam')->balanceInRange($account, $start, clone $end); $range = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
// 2022-10-11 this method no longer converts to float. $previous = array_values($range)[0][$field];
$previous = array_values($range)[0];
while ($currentStart <= $end) { while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format] : $previous; $balance = array_key_exists($format, $range) ? $range[$format][$field] : $previous;
$previous = $balance; $previous = $balance;
$currentStart->addDay(); $currentStart->addDay();
$currentSet['entries'][$label] = $balance; $currentSet['entries'][$label] = $balance;

View File

@ -28,6 +28,9 @@ use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException; use Carbon\Exceptions\InvalidDateException;
use Carbon\Exceptions\InvalidFormatException; use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Bus\DispatchesJobs;
@ -55,6 +58,8 @@ abstract class Controller extends BaseController
/** @var array<int, string> */ /** @var array<int, string> */
protected array $allowedSort; protected array $allowedSort;
protected ParameterBag $parameters; protected ParameterBag $parameters;
protected bool $convertToNative = false;
protected TransactionCurrency $defaultCurrency;
/** /**
* Controller constructor. * Controller constructor.
@ -67,8 +72,11 @@ abstract class Controller extends BaseController
function ($request, $next) { function ($request, $next) {
$this->parameters = $this->getParameters(); $this->parameters = $this->getParameters();
if (auth()->check()) { if (auth()->check()) {
$language = app('steam')->getLanguage(); $language = Steam::getLanguage();
$this->convertToNative = Amount::convertToNative();
$this->defaultCurrency = Amount::getDefaultCurrency();
app()->setLocale($language); app()->setLocale($language);
} }
return $next($request); return $next($request);
@ -82,7 +90,7 @@ abstract class Controller extends BaseController
private function getParameters(): ParameterBag private function getParameters(): ParameterBag
{ {
$bag = new ParameterBag(); $bag = new ParameterBag();
$page = (int)request()->get('page'); $page = (int) request()->get('page');
if ($page < 1) { if ($page < 1) {
$page = 1; $page = 1;
} }
@ -107,13 +115,13 @@ abstract class Controller extends BaseController
$obj = null; $obj = null;
if (null !== $date) { if (null !== $date) {
try { try {
$obj = Carbon::parse((string)$date); $obj = Carbon::parse((string) $date);
} catch (InvalidDateException|InvalidFormatException $e) { } catch (InvalidDateException|InvalidFormatException $e) {
// don't care // don't care
app('log')->warning( app('log')->warning(
sprintf( sprintf(
'Ignored invalid date "%s" in API controller parameter check: %s', 'Ignored invalid date "%s" in API controller parameter check: %s',
substr((string)$date, 0, 20), substr((string) $date, 0, 20),
$e->getMessage() $e->getMessage()
) )
); );
@ -134,7 +142,7 @@ abstract class Controller extends BaseController
$value = null; $value = null;
} }
if (null !== $value) { if (null !== $value) {
$bag->set($integer, (int)$value); $bag->set($integer, (int) $value);
} }
if (null === $value if (null === $value
&& 'limit' === $integer // @phpstan-ignore-line && 'limit' === $integer // @phpstan-ignore-line
@ -144,7 +152,7 @@ abstract class Controller extends BaseController
$user = auth()->user(); $user = auth()->user();
/** @var Preference $pageSize */ /** @var Preference $pageSize */
$pageSize = (int)app('preferences')->getForUser($user, 'listPageSize', 50)->data; $pageSize = (int) app('preferences')->getForUser($user, 'listPageSize', 50)->data;
$bag->set($integer, $pageSize); $bag->set($integer, $pageSize);
} }
} }
@ -158,7 +166,7 @@ abstract class Controller extends BaseController
$sortParameters = []; $sortParameters = [];
try { try {
$param = (string)request()->query->get('sort'); $param = (string) request()->query->get('sort');
} catch (BadRequestException $e) { } catch (BadRequestException $e) {
app('log')->error('Request field "sort" contains a non-scalar value. Value set to NULL.'); app('log')->error('Request field "sort" contains a non-scalar value. Value set to NULL.');
app('log')->error($e->getMessage()); app('log')->error($e->getMessage());

View File

@ -70,8 +70,8 @@ class TransactionController extends Controller
// to respond to what is in the $query. // to respond to what is in the $query.
// this is OK because only one thing can be in the query at the moment. // this is OK because only one thing can be in the query at the moment.
if ($this->isUpdateTransactionAccount($params)) { if ($this->isUpdateTransactionAccount($params)) {
$original = $this->repository->find((int)$params['where']['account_id']); $original = $this->repository->find((int) $params['where']['account_id']);
$destination = $this->repository->find((int)$params['update']['account_id']); $destination = $this->repository->find((int) $params['update']['account_id']);
/** @var AccountDestroyService $service */ /** @var AccountDestroyService $service */
$service = app(AccountDestroyService::class); $service = app(AccountDestroyService::class);

View File

@ -26,10 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Data;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DestroyRequest; use FireflyIII\Api\V1\Requests\Data\DestroyRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@ -66,9 +66,9 @@ class DestroyController extends Controller
$objects = $request->getObjects(); $objects = $request->getObjects();
$this->unused = $request->boolean('unused', false); $this->unused = $request->boolean('unused', false);
$allExceptAssets = [AccountType::BENEFICIARY, AccountType::CASH, AccountType::CREDITCARD, AccountType::DEFAULT, AccountType::EXPENSE, AccountType::IMPORT, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT, AccountType::RECONCILIATION, AccountType::REVENUE]; $allExceptAssets = [AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::REVENUE->value];
$all = [AccountType::ASSET, AccountType::BENEFICIARY, AccountType::CASH, AccountType::CREDITCARD, AccountType::DEBT, AccountType::DEFAULT, AccountType::EXPENSE, AccountType::IMPORT, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::RECONCILIATION]; $all = [AccountTypeEnum::ASSET->value, AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::RECONCILIATION->value];
$liabilities = [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD]; $liabilities = [AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::CREDITCARD->value];
$transactions = [TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value, TransactionTypeEnum::RECONCILIATION->value]; $transactions = [TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value, TransactionTypeEnum::RECONCILIATION->value];
match ($objects) { match ($objects) {
@ -82,9 +82,9 @@ class DestroyController extends Controller
'object_groups' => $this->destroyObjectGroups(), 'object_groups' => $this->destroyObjectGroups(),
'not_assets_liabilities' => $this->destroyAccounts($allExceptAssets), 'not_assets_liabilities' => $this->destroyAccounts($allExceptAssets),
'accounts' => $this->destroyAccounts($all), 'accounts' => $this->destroyAccounts($all),
'asset_accounts' => $this->destroyAccounts([AccountType::ASSET, AccountType::DEFAULT]), 'asset_accounts' => $this->destroyAccounts([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]),
'expense_accounts' => $this->destroyAccounts([AccountType::BENEFICIARY, AccountType::EXPENSE]), 'expense_accounts' => $this->destroyAccounts([AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::EXPENSE->value]),
'revenue_accounts' => $this->destroyAccounts([AccountType::REVENUE]), 'revenue_accounts' => $this->destroyAccounts([AccountTypeEnum::REVENUE->value]),
'liabilities' => $this->destroyAccounts($liabilities), 'liabilities' => $this->destroyAccounts($liabilities),
'transactions' => $this->destroyTransactions($transactions), 'transactions' => $this->destroyTransactions($transactions),
'withdrawals' => $this->destroyTransactions([TransactionTypeEnum::WITHDRAWAL->value]), 'withdrawals' => $this->destroyTransactions([TransactionTypeEnum::WITHDRAWAL->value]),

View File

@ -88,7 +88,7 @@ class ExportController extends Controller
->header('Expires', '0') ->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') ->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public') ->header('Pragma', 'public')
->header('Content-Length', (string)strlen($data[$key])) ->header('Content-Length', (string) strlen($data[$key]))
; ;
return $response; return $response;

View File

@ -29,13 +29,13 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\Tag; use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@ -63,14 +63,17 @@ class PurgeController extends Controller
Bill::whereUserId($user->id)->onlyTrashed()->forceDelete(); Bill::whereUserId($user->id)->onlyTrashed()->forceDelete();
// piggies // piggies
$set = PiggyBank::leftJoin('accounts', 'accounts.id', 'piggy_banks.account_id') $repository = app(PiggyBankRepositoryInterface::class);
->where('accounts.user_id', $user->id)->onlyTrashed()->get(['piggy_banks.*']) $repository->setUser($user);
; $repository->purgeAll();
// $set = PiggyBank::leftJoin('accounts', 'accounts.id', 'piggy_banks.account_id')
/** @var PiggyBank $piggy */ // ->where('accounts.user_id', $user->id)->onlyTrashed()->get(['piggy_banks.*'])
foreach ($set as $piggy) { // ;
$piggy->forceDelete(); //
} // /** @var PiggyBank $piggy */
// foreach ($set as $piggy) {
// $piggy->forceDelete();
// }
// rule group // rule group
RuleGroup::whereUserId($user->id)->onlyTrashed()->forceDelete(); RuleGroup::whereUserId($user->id)->onlyTrashed()->forceDelete();

View File

@ -79,11 +79,11 @@ class AccountController extends Controller
/** @var array $expense */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'id' => (string)$expense['id'], 'id' => (string) $expense['id'],
'name' => $expense['name'], 'name' => $expense['name'],
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // intentional float 'difference_float' => (float) $expense['sum'], // intentional float
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }
@ -107,11 +107,11 @@ class AccountController extends Controller
/** @var array $expense */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'id' => (string)$expense['id'], 'id' => (string) $expense['id'],
'name' => $expense['name'], 'name' => $expense['name'],
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // intentional float 'difference_float' => (float) $expense['sum'], // intentional float
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }

View File

@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/** /**
* Class BillController * Class BillController
@ -67,6 +69,8 @@ class BillController extends Controller
$bills = $request->getBills(); $bills = $request->getBills();
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$response = []; $response = [];
// get all bills: // get all bills:
@ -81,33 +85,36 @@ class BillController extends Controller
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$billId = (int)$journal['bill_id']; $billId = (int) $journal['bill_id'];
$currencyId = (int)$journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $currencyCode = $journal['currency_code'];
$field = 'amount';
// use the native amount if the user wants to convert to native currency
if ($convertToNative && $currencyId !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
$field = 'native_amount';
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
Log::debug(sprintf('Journal #%d in bill #%d will use %s (%s %s)', $journal['transaction_group_id'], $billId, $field, $currencyCode, $journal[$field] ?? '0'));
$key = sprintf('%d-%d', $billId, $currencyId); $key = sprintf('%d-%d', $billId, $currencyId);
$foreignKey = sprintf('%d-%d', $billId, $foreignCurrencyId);
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string)$billId, 'id' => (string) $billId,
'name' => $journal['bill_name'], 'name' => $journal['bill_name'],
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], $journal['amount']); $response[$key]['difference'] = bcadd($response[$key]['difference'], (string) ($journal[$field] ?? '0'));
$response[$key]['difference_float'] = (float)$response[$key]['difference']; // intentional float $response[$key]['difference_float'] = (float) $response[$key]['difference']; // intentional float
}
if (0 !== $foreignCurrencyId) {
$response[$foreignKey] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], $journal['foreign_amount']);
$response[$foreignKey]['difference_float'] = (float)$response[$foreignKey]['difference']; // intentional float
} }
} }
@ -125,6 +132,8 @@ class BillController extends Controller
$accounts = $request->getAssetAccounts(); $accounts = $request->getAssetAccounts();
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$response = []; $response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
@ -135,28 +144,31 @@ class BillController extends Controller
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $currencyCode = $journal['currency_code'];
$field = 'amount';
// use the native amount if the user wants to convert to native currency
if ($convertToNative && $currencyId !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
$field = 'native_amount';
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
Log::debug(sprintf('Journal #%d will use %s (%s %s)', $journal['transaction_group_id'], $field, $currencyCode, $journal[$field] ?? '0'));
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], (string) ($journal[$field] ?? '0'));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; // intentional float $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference']; // intentional float
} }
} }

View File

@ -85,11 +85,11 @@ class BudgetController extends Controller
/** @var array $expense */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'id' => (string)$budget->id, 'id' => (string) $budget->id,
'name' => $budget->name, 'name' => $budget->name,
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // intentional float 'difference_float' => (float) $expense['sum'], // intentional float
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }
@ -114,8 +114,8 @@ class BudgetController extends Controller
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // intentional float 'difference_float' => (float) $expense['sum'], // intentional float
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }

View File

@ -85,11 +85,11 @@ class CategoryController extends Controller
/** @var array $expense */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'id' => (string)$category->id, 'id' => (string) $category->id,
'name' => $category->name, 'name' => $category->name,
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // intentional float 'difference_float' => (float) $expense['sum'], // intentional float
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }
@ -114,8 +114,8 @@ class CategoryController extends Controller
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // intentional float 'difference_float' => (float) $expense['sum'], // intentional float
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }

View File

@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest; use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/** /**
* Class PeriodController * Class PeriodController
@ -45,35 +47,45 @@ class PeriodController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) // collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; // same code as many other sumExpense methods. I think this needs some kind of generic method.
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $amount = '0';
$currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) {
$currencyId = $journal['foreign_currency_id'];
$currencyCode = $journal['foreign_currency_code'];
}
Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
}
if (!$convertToNative) {
// ignore the amount in foreign currency.
Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
$amount = $journal['amount'];
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $amount);
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; // intentional float $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference']; // intentional float
}
} }
return response()->json(array_values($response)); return response()->json(array_values($response));

View File

@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/** /**
* Class TagController * Class TagController
@ -66,6 +68,8 @@ class TagController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
@ -75,29 +79,36 @@ class TagController extends Controller
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; // same code as many other sumExpense methods. I think this needs some kind of generic method.
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $amount = '0';
$currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) {
$currencyId = $journal['foreign_currency_id'];
$currencyCode = $journal['foreign_currency_code'];
}
Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
}
if (!$convertToNative) {
// ignore the amount in foreign currency.
Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
$amount = $journal['amount'];
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $amount);
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; // float but on purpose. $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference']; // float but on purpose.
}
} }
return response()->json(array_values($response)); return response()->json(array_values($response));
@ -130,8 +141,8 @@ class TagController extends Controller
/** @var array $journal */ /** @var array $journal */
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $foreignCurrencyId = (int) $journal['foreign_currency_id'];
/** @var array $tag */ /** @var array $tag */
foreach ($journal['tags'] as $tag) { foreach ($journal['tags'] as $tag) {
@ -142,15 +153,15 @@ class TagController extends Controller
// on currency ID // on currency ID
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string)$tagId, 'id' => (string) $tagId,
'name' => $tag['name'], 'name' => $tag['name'],
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], $journal['amount']); $response[$key]['difference'] = bcadd($response[$key]['difference'], $journal['amount']);
$response[$key]['difference_float'] = (float)$response[$key]['difference']; // float but on purpose. $response[$key]['difference_float'] = (float) $response[$key]['difference']; // float but on purpose.
} }
// on foreign ID // on foreign ID
@ -158,11 +169,11 @@ class TagController extends Controller
$response[$foreignKey] = $journal[$foreignKey] ?? [ $response[$foreignKey] = $journal[$foreignKey] ?? [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId, 'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'], 'currency_code' => $journal['foreign_currency_code'],
]; ];
$response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], $journal['foreign_amount']); $response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], $journal['foreign_amount']);
$response[$foreignKey]['difference_float'] = (float)$response[$foreignKey]['difference']; // float but on purpose. $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // float but on purpose.
} }
} }
} }

View File

@ -73,17 +73,18 @@ class AccountController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$assetAccounts = $request->getAssetAccounts(); $assetAccounts = $request->getAssetAccounts();
$income = $this->opsRepository->sumIncomeByDestination($start, $end, $assetAccounts); $income = $this->opsRepository->sumIncomeByDestination($start, $end, $assetAccounts);
$result = []; $result = [];
/** @var array $entry */ /** @var array $entry */
foreach ($income as $entry) { foreach ($income as $entry) {
$result[] = [ $result[] = [
'id' => (string)$entry['id'], 'id' => (string) $entry['id'],
'name' => $entry['name'], 'name' => $entry['name'],
'difference' => $entry['sum'], 'difference' => $entry['sum'],
'difference_float' => (float)$entry['sum'], // float but on purpose. 'difference_float' => (float) $entry['sum'], // float but on purpose.
'currency_id' => (string)$entry['currency_id'], 'currency_id' => (string) $entry['currency_id'],
'currency_code' => $entry['currency_code'], 'currency_code' => $entry['currency_code'],
]; ];
} }
@ -107,11 +108,11 @@ class AccountController extends Controller
/** @var array $entry */ /** @var array $entry */
foreach ($income as $entry) { foreach ($income as $entry) {
$result[] = [ $result[] = [
'id' => (string)$entry['id'], 'id' => (string) $entry['id'],
'name' => $entry['name'], 'name' => $entry['name'],
'difference' => $entry['sum'], 'difference' => $entry['sum'],
'difference_float' => (float)$entry['sum'], // float but on purpose. 'difference_float' => (float) $entry['sum'], // float but on purpose.
'currency_id' => (string)$entry['currency_id'], 'currency_id' => (string) $entry['currency_id'],
'currency_code' => $entry['currency_code'], 'currency_code' => $entry['currency_code'],
]; ];
} }

View File

@ -85,11 +85,11 @@ class CategoryController extends Controller
/** @var array $expense */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'id' => (string)$category->id, 'id' => (string) $category->id,
'name' => $category->name, 'name' => $category->name,
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // float but on purpose. 'difference_float' => (float) $expense['sum'], // float but on purpose.
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }
@ -114,8 +114,8 @@ class CategoryController extends Controller
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], // float but on purpose. 'difference_float' => (float) $expense['sum'], // float but on purpose.
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }

View File

@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest; use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
/** /**
@ -45,38 +46,37 @@ class PeriodController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) // collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; // currency
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount'])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; // float but on purpose. $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference']; // float but on purpose.
}
} }
return response()->json(array_values($response)); return response()->json(array_values($response));

View File

@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
/** /**
@ -67,6 +68,8 @@ class TagController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
@ -76,32 +79,30 @@ class TagController extends Controller
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; // currency
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount'])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
} }
return response()->json(array_values($response)); return response()->json(array_values($response));
@ -134,8 +135,8 @@ class TagController extends Controller
/** @var array $journal */ /** @var array $journal */
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $foreignCurrencyId = (int) $journal['foreign_currency_id'];
/** @var array $tag */ /** @var array $tag */
foreach ($journal['tags'] as $tag) { foreach ($journal['tags'] as $tag) {
@ -146,15 +147,15 @@ class TagController extends Controller
// on currency ID // on currency ID
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string)$tagId, 'id' => (string) $tagId,
'name' => $tag['name'], 'name' => $tag['name'],
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], app('steam')->positive($journal['amount'])); $response[$key]['difference'] = bcadd($response[$key]['difference'], app('steam')->positive($journal['amount']));
$response[$key]['difference_float'] = (float)$response[$key]['difference']; $response[$key]['difference_float'] = (float) $response[$key]['difference'];
} }
// on foreign ID // on foreign ID
@ -162,14 +163,14 @@ class TagController extends Controller
$response[$foreignKey] = $journal[$foreignKey] ?? [ $response[$foreignKey] = $journal[$foreignKey] ?? [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId, 'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'], 'currency_code' => $journal['foreign_currency_code'],
]; ];
$response[$foreignKey]['difference'] = bcadd( $response[$foreignKey]['difference'] = bcadd(
$response[$foreignKey]['difference'], $response[$foreignKey]['difference'],
app('steam')->positive($journal['foreign_amount']) app('steam')->positive($journal['foreign_amount'])
); );
$response[$foreignKey]['difference_float'] = (float)$response[$foreignKey]['difference']; $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference'];
} }
} }
} }

View File

@ -85,11 +85,11 @@ class CategoryController extends Controller
/** @var array $expense */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'id' => (string)$category->id, 'id' => (string) $category->id,
'name' => $category->name, 'name' => $category->name,
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], 'difference_float' => (float) $expense['sum'],
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }
@ -114,8 +114,8 @@ class CategoryController extends Controller
foreach ($expenses as $expense) { foreach ($expenses as $expense) {
$result[] = [ $result[] = [
'difference' => $expense['sum'], 'difference' => $expense['sum'],
'difference_float' => (float)$expense['sum'], 'difference_float' => (float) $expense['sum'],
'currency_id' => (string)$expense['currency_id'], 'currency_id' => (string) $expense['currency_id'],
'currency_code' => $expense['currency_code'], 'currency_code' => $expense['currency_code'],
]; ];
} }

View File

@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest; use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
/** /**
@ -45,38 +46,38 @@ class PeriodController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) // collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts); $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; // currency
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount'])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
} }
return response()->json(array_values($response)); return response()->json(array_values($response));

View File

@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
/** /**
@ -65,6 +66,9 @@ class TagController extends Controller
$start = $request->getStart(); $start = $request->getStart();
$end = $request->getEnd(); $end = $request->getEnd();
$response = []; $response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts. // collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
@ -74,32 +78,30 @@ class TagController extends Controller
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; // currency
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [ $response[$currencyId] ??= [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount'])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float)$response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float)$response[$foreignCurrencyId]['difference'];
}
} }
return response()->json(array_values($response)); return response()->json(array_values($response));
@ -132,8 +134,8 @@ class TagController extends Controller
/** @var array $journal */ /** @var array $journal */
foreach ($genericSet as $journal) { foreach ($genericSet as $journal) {
$currencyId = (int)$journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int)$journal['foreign_currency_id']; $foreignCurrencyId = (int) $journal['foreign_currency_id'];
/** @var array $tag */ /** @var array $tag */
foreach ($journal['tags'] as $tag) { foreach ($journal['tags'] as $tag) {
@ -144,15 +146,15 @@ class TagController extends Controller
// on currency ID // on currency ID
if (0 !== $currencyId) { if (0 !== $currencyId) {
$response[$key] ??= [ $response[$key] ??= [
'id' => (string)$tagId, 'id' => (string) $tagId,
'name' => $tag['name'], 'name' => $tag['name'],
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], app('steam')->positive($journal['amount'])); $response[$key]['difference'] = bcadd($response[$key]['difference'], app('steam')->positive($journal['amount']));
$response[$key]['difference_float'] = (float)$response[$key]['difference']; $response[$key]['difference_float'] = (float) $response[$key]['difference'];
} }
// on foreign ID // on foreign ID
@ -160,14 +162,14 @@ class TagController extends Controller
$response[$foreignKey] = $journal[$foreignKey] ?? [ $response[$foreignKey] = $journal[$foreignKey] ?? [
'difference' => '0', 'difference' => '0',
'difference_float' => 0, 'difference_float' => 0,
'currency_id' => (string)$foreignCurrencyId, 'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'], 'currency_code' => $journal['foreign_currency_code'],
]; ];
$response[$foreignKey]['difference'] = bcadd( $response[$foreignKey]['difference'] = bcadd(
$response[$foreignKey]['difference'], $response[$foreignKey]['difference'],
app('steam')->positive($journal['foreign_amount']) app('steam')->positive($journal['foreign_amount'])
); );
$response[$foreignKey]['difference_float'] = (float)$response[$foreignKey]['difference']; // intentional float $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float
} }
} }
} }

View File

@ -111,7 +111,7 @@ class ListController extends Controller
// types to get, page size: // types to get, page size:
$pageSize = $this->parameters->get('limit'); $pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it. // get list of piggy banks. Count it and split it.
$collection = $this->repository->getPiggyBanks($account); $collection = $this->repository->getPiggyBanks($account);
$count = $collection->count(); $count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@ -105,7 +105,7 @@ class ShowController extends Controller
->header('Expires', '0') ->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') ->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public') ->header('Pragma', 'public')
->header('Content-Length', (string)strlen($content)) ->header('Content-Length', (string) strlen($content))
; ;
return $response; return $response;

View File

@ -69,6 +69,7 @@ class StoreController extends Controller
$data = $request->getAll(); $data = $request->getAll();
$data['start_date'] = $data['start']; $data['start_date'] = $data['start'];
$data['end_date'] = $data['end']; $data['end_date'] = $data['end'];
$data['notes'] = $data['notes'];
$data['budget_id'] = $budget->id; $data['budget_id'] = $budget->id;
$budgetLimit = $this->blRepository->store($data); $budgetLimit = $this->blRepository->store($data);

View File

@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@ -58,6 +59,38 @@ class ListController extends Controller
); );
} }
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/piggy_banks/listAccountByPiggyBank
*
* List single resource.
*
* @throws FireflyException
*/
public function accounts(PiggyBank $piggyBank): JsonResponse
{
// types to get, page size:
$pageSize = $this->parameters->get('limit');
$manager = $this->getManager();
$collection = $piggyBank->accounts;
$count = $collection->count();
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy-banks.accounts', [$piggyBank->id]).$this->buildParams());
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($events, $transformer, 'accounts');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/** /**
* This endpoint is documented at: * This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/piggy_banks/listAttachmentByPiggyBank * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/piggy_banks/listAttachmentByPiggyBank

View File

@ -72,7 +72,7 @@ class ShowController extends Controller
// types to get, page size: // types to get, page size:
$pageSize = $this->parameters->get('limit'); $pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it. // get list of piggy banks. Count it and split it.
$collection = $this->repository->getPiggyBanks(); $collection = $this->repository->getPiggyBanks();
$count = $collection->count(); $count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@ -91,7 +91,7 @@ class ListController extends Controller
// filter list on currency preference: // filter list on currency preference:
$collection = $unfiltered->filter( $collection = $unfiltered->filter(
static function (Account $account) use ($currency, $accountRepository) { static function (Account $account) use ($currency, $accountRepository) {
$currencyId = (int)$accountRepository->getMetaValue($account, 'currency_id'); $currencyId = (int) $accountRepository->getMetaValue($account, 'currency_id');
return $currencyId === $currency->id; return $currencyId === $currency->id;
} }

View File

@ -107,8 +107,7 @@ class ShowController extends Controller
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$manager = $this->getManager(); $manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup); $this->parameters->set('defaultCurrency', $this->defaultCurrency);
$this->parameters->set('defaultCurrency', $defaultCurrency);
// update fields with user info. // update fields with user info.
$currency->refreshForUser($user); $currency->refreshForUser($user);
@ -135,7 +134,7 @@ class ShowController extends Controller
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$manager = $this->getManager(); $manager = $this->getManager();
$currency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup); $currency = $this->defaultCurrency;
// update fields with user info. // update fields with user info.
$currency->refreshForUser($user); $currency->refreshForUser($user);

View File

@ -62,14 +62,14 @@ class AccountController extends Controller
*/ */
public function search(Request $request): JsonResponse|Response public function search(Request $request): JsonResponse|Response
{ {
app('log')->debug('Now in account search()');
$manager = $this->getManager(); $manager = $this->getManager();
$query = trim((string)$request->get('query')); $query = trim((string) $request->get('query'));
$field = trim((string)$request->get('field')); $field = trim((string) $request->get('field'));
$type = $request->get('type') ?? 'all'; $type = $request->get('type') ?? 'all';
if ('' === $query || !in_array($field, $this->validFields, true)) { if ('' === $query || !in_array($field, $this->validFields, true)) {
return response(null, 422); return response(null, 422);
} }
app('log')->debug(sprintf('Now in account search("%s", "%s")', $field, $query));
$types = $this->mapAccountTypes($type); $types = $this->mapAccountTypes($type);
/** @var AccountSearch $search */ /** @var AccountSearch $search */

View File

@ -47,8 +47,8 @@ class TransactionController extends Controller
public function search(Request $request, SearchInterface $searcher): JsonResponse public function search(Request $request, SearchInterface $searcher): JsonResponse
{ {
$manager = $this->getManager(); $manager = $this->getManager();
$fullQuery = (string)$request->get('query'); $fullQuery = (string) $request->get('query');
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page'); $page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
$pageSize = $this->parameters->get('limit'); $pageSize = $this->parameters->get('limit');
$searcher->parseQuery($fullQuery); $searcher->parseQuery($fullQuery);
$searcher->setPage($page); $searcher->setPage($page);

View File

@ -27,19 +27,21 @@ namespace FireflyIII\Api\V1\Controllers\Summary;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest; use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Report\NetWorthInterface; use FireflyIII\Helpers\Report\NetWorthInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface; use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/** /**
* Class BasicController * Class BasicController
@ -120,6 +122,9 @@ class BasicController extends Controller
private function getBalanceInformation(Carbon $start, Carbon $end): array private function getBalanceInformation(Carbon $start, Carbon $end): array
{ {
// some config settings
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// prep some arrays: // prep some arrays:
$incomes = []; $incomes = [];
$expenses = []; $expenses = [];
@ -133,16 +138,17 @@ class BasicController extends Controller
$set = $collector->getExtractedJournals(); $set = $collector->getExtractedJournals();
/** @var array $transactionJournal */ /** @var array $journal */
foreach ($set as $transactionJournal) { foreach ($set as $journal) {
$currencyId = (int)$transactionJournal['currency_id']; $currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$incomes[$currencyId] ??= '0'; $incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd( $incomes[$currencyId] = bcadd(
$incomes[$currencyId], $incomes[$currencyId],
bcmul($transactionJournal['amount'], '-1') bcmul($amount, '-1')
); );
$sums[$currencyId] ??= '0'; $sums[$currencyId] ??= '0';
$sums[$currencyId] = bcadd($sums[$currencyId], bcmul($transactionJournal['amount'], '-1')); $sums[$currencyId] = bcadd($sums[$currencyId], bcmul($amount, '-1'));
} }
// collect expenses of user using the new group collector. // collect expenses of user using the new group collector.
@ -151,13 +157,14 @@ class BasicController extends Controller
$collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
$set = $collector->getExtractedJournals(); $set = $collector->getExtractedJournals();
/** @var array $transactionJournal */ /** @var array $journal */
foreach ($set as $transactionJournal) { foreach ($set as $journal) {
$currencyId = (int)$transactionJournal['currency_id']; $currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$expenses[$currencyId] ??= '0'; $expenses[$currencyId] ??= '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $transactionJournal['amount']); $expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
$sums[$currencyId] ??= '0'; $sums[$currencyId] ??= '0';
$sums[$currencyId] = bcadd($sums[$currencyId], $transactionJournal['amount']); $sums[$currencyId] = bcadd($sums[$currencyId], $amount);
} }
// format amounts: // format amounts:
@ -172,7 +179,7 @@ class BasicController extends Controller
'key' => sprintf('balance-in-%s', $currency->code), 'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $sums[$currencyId] ?? '0', 'monetary_value' => $sums[$currencyId] ?? '0',
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@ -185,7 +192,7 @@ class BasicController extends Controller
'key' => sprintf('spent-in-%s', $currency->code), 'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $expenses[$currencyId] ?? '0', 'monetary_value' => $expenses[$currencyId] ?? '0',
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@ -197,7 +204,7 @@ class BasicController extends Controller
'key' => sprintf('earned-in-%s', $currency->code), 'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $incomes[$currencyId] ?? '0', 'monetary_value' => $incomes[$currencyId] ?? '0',
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@ -231,7 +238,7 @@ class BasicController extends Controller
'key' => sprintf('bills-paid-in-%s', $info['code']), 'key' => sprintf('bills-paid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => (string)$info['id'], 'currency_id' => (string) $info['id'],
'currency_code' => $info['code'], 'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'], 'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'], 'currency_decimal_places' => $info['decimal_places'],
@ -250,7 +257,7 @@ class BasicController extends Controller
'key' => sprintf('bills-unpaid-in-%s', $info['code']), 'key' => sprintf('bills-unpaid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => (string)$info['id'], 'currency_id' => (string) $info['id'],
'currency_code' => $info['code'], 'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'], 'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'], 'currency_decimal_places' => $info['decimal_places'],
@ -269,29 +276,32 @@ class BasicController extends Controller
*/ */
private function getLeftToSpendInfo(Carbon $start, Carbon $end): array private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
{ {
Log::debug(sprintf('Now in getLeftToSpendInfo("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$return = []; $return = [];
$today = today(config('app.timezone')); $today = today(config('app.timezone'));
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end); $available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
$budgets = $this->budgetRepository->getActiveBudgets(); $budgets = $this->budgetRepository->getActiveBudgets();
$spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets); $spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets);
$days = (int) $today->diffInDays($end, true) + 1;
foreach ($spent as $row) { foreach ($spent as $row) {
// either an amount was budgeted or 0 is available. // either an amount was budgeted or 0 is available.
$amount = (string)($available[$row['currency_id']] ?? '0'); $currencyId = $row['currency_id'];
$amount = (string) ($available[$currencyId] ?? '0');
$spentInCurrency = $row['sum']; $spentInCurrency = $row['sum'];
$leftToSpend = bcadd($amount, $spentInCurrency); $leftToSpend = bcadd($amount, $spentInCurrency);
$days = (int)$today->diffInDays($end, true) + 1;
$perDay = '0'; $perDay = '0';
if (0 !== $days && bccomp($leftToSpend, '0') > -1) { if (0 !== $days && bccomp($leftToSpend, '0') > -1) {
$perDay = bcdiv($leftToSpend, (string)$days); $perDay = bcdiv($leftToSpend, (string) $days);
} }
Log::debug(sprintf('Spent %s %s', $row['currency_code'], $row['sum']));
$return[] = [ $return[] = [
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]), 'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
'monetary_value' => $leftToSpend, 'monetary_value' => $leftToSpend,
'currency_id' => (string)$row['currency_id'], 'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => $row['currency_decimal_places'],
@ -311,9 +321,11 @@ class BasicController extends Controller
private function getNetWorthInfo(Carbon $start, Carbon $end): array private function getNetWorthInfo(Carbon $start, Carbon $end): array
{ {
Log::debug('getNetWorthInfo');
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$date = today(config('app.timezone'))->startOfDay(); $date = now(config('app.timezone'));
// start and end in the future? use $end // start and end in the future? use $end
if ($this->notInDateRange($date, $start, $end)) { if ($this->notInDateRange($date, $start, $end)) {
/** @var Carbon $date */ /** @var Carbon $date */
@ -323,9 +335,7 @@ class BasicController extends Controller
/** @var NetWorthInterface $netWorthHelper */ /** @var NetWorthInterface $netWorthHelper */
$netWorthHelper = app(NetWorthInterface::class); $netWorthHelper = app(NetWorthInterface::class);
$netWorthHelper->setUser($user); $netWorthHelper->setUser($user);
$allAccounts = $this->accountRepository->getActiveAccountsByType( $allAccounts = $this->accountRepository->getActiveAccountsByType([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::DEBT->value]);
[AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]
);
// filter list on preference of being included. // filter list on preference of being included.
$filtered = $allAccounts->filter( $filtered = $allAccounts->filter(
@ -351,7 +361,7 @@ class BasicController extends Controller
'key' => sprintf('net-worth-in-%s', $data['currency_code']), 'key' => sprintf('net-worth-in-%s', $data['currency_code']),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $data['currency_symbol']]), 'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $data['currency_symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => (string)$data['currency_id'], 'currency_id' => (string) $data['currency_id'],
'currency_code' => $data['currency_code'], 'currency_code' => $data['currency_code'],
'currency_symbol' => $data['currency_symbol'], 'currency_symbol' => $data['currency_symbol'],
'currency_decimal_places' => $data['currency_decimal_places'], 'currency_decimal_places' => $data['currency_decimal_places'],
@ -360,6 +370,7 @@ class BasicController extends Controller
'sub_title' => '', 'sub_title' => '',
]; ];
} }
Log::debug('End of getNetWorthInfo');
return $return; return $return;
} }

View File

@ -101,8 +101,8 @@ class ConfigurationController extends Controller
return [ return [
'is_demo_site' => $isDemoSite?->data, 'is_demo_site' => $isDemoSite?->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data, 'permission_update_check' => null === $updateCheck ? null : (int) $updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data, 'last_update_check' => null === $lastCheck ? null : (int) $lastCheck->data,
'single_user_mode' => $singleUser?->data, 'single_user_mode' => $singleUser?->data,
]; ];
} }

View File

@ -83,12 +83,12 @@ class MoveTransactionsRequest extends FormRequest
$data = $validator->getData(); $data = $validator->getData();
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user()); $repository->setUser(auth()->user());
$original = $repository->find((int)$data['original_account']); $original = $repository->find((int) $data['original_account']);
$destination = $repository->find((int)$data['destination_account']); $destination = $repository->find((int) $data['destination_account']);
// not the same type: // not the same type:
if ($original->accountType->type !== $destination->accountType->type) { if ($original->accountType->type !== $destination->accountType->type) {
$validator->errors()->add('title', (string)trans('validation.same_account_type')); $validator->errors()->add('title', (string) trans('validation.same_account_type'));
return; return;
} }
@ -98,7 +98,7 @@ class MoveTransactionsRequest extends FormRequest
// check different scenario's. // check different scenario's.
if (null === $originalCurrency xor null === $destinationCurrency) { if (null === $originalCurrency xor null === $destinationCurrency) {
$validator->errors()->add('title', (string)trans('validation.same_account_currency')); $validator->errors()->add('title', (string) trans('validation.same_account_currency'));
return; return;
} }
@ -107,7 +107,7 @@ class MoveTransactionsRequest extends FormRequest
return; return;
} }
if ($originalCurrency->code !== $destinationCurrency->code) { if ($originalCurrency->code !== $destinationCurrency->code) {
$validator->errors()->add('title', (string)trans('validation.same_account_currency')); $validator->errors()->add('title', (string) trans('validation.same_account_currency'));
} }
} }
} }

View File

@ -52,7 +52,7 @@ class ExportRequest extends FormRequest
$accounts = new Collection(); $accounts = new Collection();
foreach ($parts as $part) { foreach ($parts as $part) {
$accountId = (int)$part; $accountId = (int) $part;
if (0 !== $accountId) { if (0 !== $accountId) {
$account = $repository->find($accountId); $account = $repository->find($accountId);
if (null !== $account && AccountType::ASSET === $account->accountType->type) { if (null !== $account && AccountType::ASSET === $account->accountType->type) {

View File

@ -88,7 +88,7 @@ class GenericRequest extends FormRequest
$array = $this->get('accounts'); $array = $this->get('accounts');
if (is_array($array)) { if (is_array($array)) {
foreach ($array as $accountId) { foreach ($array as $accountId) {
$accountId = (int)$accountId; $accountId = (int) $accountId;
$account = $repository->find($accountId); $account = $repository->find($accountId);
if (null !== $account) { if (null !== $account) {
$this->accounts->push($account); $this->accounts->push($account);
@ -114,7 +114,7 @@ class GenericRequest extends FormRequest
$array = $this->get('bills'); $array = $this->get('bills');
if (is_array($array)) { if (is_array($array)) {
foreach ($array as $billId) { foreach ($array as $billId) {
$billId = (int)$billId; $billId = (int) $billId;
$bill = $repository->find($billId); $bill = $repository->find($billId);
if (null !== $bill) { if (null !== $bill) {
$this->bills->push($bill); $this->bills->push($bill);
@ -140,7 +140,7 @@ class GenericRequest extends FormRequest
$array = $this->get('budgets'); $array = $this->get('budgets');
if (is_array($array)) { if (is_array($array)) {
foreach ($array as $budgetId) { foreach ($array as $budgetId) {
$budgetId = (int)$budgetId; $budgetId = (int) $budgetId;
$budget = $repository->find($budgetId); $budget = $repository->find($budgetId);
if (null !== $budget) { if (null !== $budget) {
$this->budgets->push($budget); $this->budgets->push($budget);
@ -166,7 +166,7 @@ class GenericRequest extends FormRequest
$array = $this->get('categories'); $array = $this->get('categories');
if (is_array($array)) { if (is_array($array)) {
foreach ($array as $categoryId) { foreach ($array as $categoryId) {
$categoryId = (int)$categoryId; $categoryId = (int) $categoryId;
$category = $repository->find($categoryId); $category = $repository->find($categoryId);
if (null !== $category) { if (null !== $category) {
$this->categories->push($category); $this->categories->push($category);
@ -240,7 +240,7 @@ class GenericRequest extends FormRequest
$array = $this->get('tags'); $array = $this->get('tags');
if (is_array($array)) { if (is_array($array)) {
foreach ($array as $tagId) { foreach ($array as $tagId) {
$tagId = (int)$tagId; $tagId = (int) $tagId;
$tag = $repository->find($tagId); $tag = $repository->find($tagId);
if (null !== $tag) { if (null !== $tag) {
$this->tags->push($tag); $this->tags->push($tag);

View File

@ -84,7 +84,7 @@ class Request extends FormRequest
$start = new Carbon($data['start']); $start = new Carbon($data['start']);
$end = new Carbon($data['end']); $end = new Carbon($data['end']);
if ($end->isBefore($start)) { if ($end->isBefore($start)) {
$validator->errors()->add('end', (string)trans('validation.date_after')); $validator->errors()->add('end', (string) trans('validation.date_after'));
} }
} }
} }

View File

@ -96,11 +96,11 @@ class StoreRequest extends FormRequest
$validator->after( $validator->after(
static function (Validator $validator): void { static function (Validator $validator): void {
$data = $validator->getData(); $data = $validator->getData();
$min = (string)($data['amount_min'] ?? '0'); $min = (string) ($data['amount_min'] ?? '0');
$max = (string)($data['amount_max'] ?? '0'); $max = (string) ($data['amount_max'] ?? '0');
if (1 === bccomp($min, $max)) { if (1 === bccomp($min, $max)) {
$validator->errors()->add('amount_min', (string)trans('validation.amount_min_over_max')); $validator->errors()->add('amount_min', (string) trans('validation.amount_min_over_max'));
} }
} }
); );

View File

@ -104,7 +104,7 @@ class UpdateRequest extends FormRequest
$max = $data['amount_max'] ?? '0'; $max = $data['amount_max'] ?? '0';
if (1 === bccomp($min, $max)) { if (1 === bccomp($min, $max)) {
$validator->errors()->add('amount_min', (string)trans('validation.amount_min_over_max')); $validator->errors()->add('amount_min', (string) trans('validation.amount_min_over_max'));
} }
} }
} }

View File

@ -48,6 +48,7 @@ class StoreRequest extends FormRequest
'amount' => $this->convertString('amount'), 'amount' => $this->convertString('amount'),
'currency_id' => $this->convertInteger('currency_id'), 'currency_id' => $this->convertInteger('currency_id'),
'currency_code' => $this->convertString('currency_code'), 'currency_code' => $this->convertString('currency_code'),
'notes' => $this->stringWithNewlines('notes'),
]; ];
} }
@ -62,6 +63,7 @@ class StoreRequest extends FormRequest
'amount' => ['required', new IsValidPositiveAmount()], 'amount' => ['required', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'notes' => 'nullable|min:0|max:32768',
]; ];
} }
} }

View File

@ -51,7 +51,12 @@ class UpdateRequest extends FormRequest
'amount' => ['amount', 'convertString'], 'amount' => ['amount', 'convertString'],
'currency_id' => ['currency_id', 'convertInteger'], 'currency_id' => ['currency_id', 'convertInteger'],
'currency_code' => ['currency_code', 'convertString'], 'currency_code' => ['currency_code', 'convertString'],
'notes' => ['notes', 'stringWithNewlines'],
]; ];
if (false === $this->has('notes')) {
// ignore notes, not submitted.
unset($fields['notes']);
}
return $this->getAllData($fields); return $this->getAllData($fields);
} }
@ -67,6 +72,7 @@ class UpdateRequest extends FormRequest
'amount' => ['nullable', new IsValidPositiveAmount()], 'amount' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'notes' => 'nullable|min:0|max:32768',
]; ];
} }
@ -84,7 +90,7 @@ class UpdateRequest extends FormRequest
$start = new Carbon($data['start']); $start = new Carbon($data['start']);
$end = new Carbon($data['end']); $end = new Carbon($data['end']);
if ($end->isBefore($start)) { if ($end->isBefore($start)) {
$validator->errors()->add('end', (string)trans('validation.date_after')); $validator->errors()->add('end', (string) trans('validation.date_after'));
} }
} }
} }

View File

@ -24,10 +24,15 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\PiggyBank; namespace FireflyIII\Api\V1\Requests\Models\PiggyBank;
use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/** /**
* Class StoreRequest * Class StoreRequest
@ -47,18 +52,38 @@ class StoreRequest extends FormRequest
]; ];
$data = $this->getAllData($fields); $data = $this->getAllData($fields);
$data['name'] = $this->convertString('name'); $data['name'] = $this->convertString('name');
$data['account_id'] = $this->convertInteger('account_id'); $data['accounts'] = $this->parseAccounts($this->get('accounts'));
$data['targetamount'] = $this->convertString('target_amount'); $data['target_amount'] = $this->convertString('target_amount');
$data['current_amount'] = $this->convertString('current_amount'); $data['start_date'] = $this->getCarbonDate('start_date');
$data['startdate'] = $this->getCarbonDate('start_date'); $data['target_date'] = $this->getCarbonDate('target_date');
$data['targetdate'] = $this->getCarbonDate('target_date');
$data['notes'] = $this->stringWithNewlines('notes'); $data['notes'] = $this->stringWithNewlines('notes');
$data['object_group_id'] = $this->convertInteger('object_group_id'); $data['object_group_id'] = $this->convertInteger('object_group_id');
$data['transaction_currency_id'] = $this->convertInteger('transaction_currency_id');
$data['transaction_currency_code'] = $this->convertString('transaction_currency_code');
$data['object_group_title'] = $this->convertString('object_group_title'); $data['object_group_title'] = $this->convertString('object_group_title');
return $data; return $data;
} }
private function parseAccounts(mixed $array): array
{
if (!is_array($array)) {
return [];
}
$return = [];
foreach ($array as $entry) {
if (!is_array($entry)) {
continue;
}
$return[] = [
'account_id' => $this->integerFromValue((string) ($entry['account_id'] ?? '0')),
'current_amount' => $this->clearString((string) ($entry['current_amount'] ?? '0')),
];
}
return $return;
}
/** /**
* The rules that the incoming request must be matched against. * The rules that the incoming request must be matched against.
*/ */
@ -66,14 +91,79 @@ class StoreRequest extends FormRequest
{ {
return [ return [
'name' => 'required|min:1|max:255|uniquePiggyBankForUser', 'name' => 'required|min:1|max:255|uniquePiggyBankForUser',
'current_amount' => ['nullable', new IsValidPositiveAmount()], 'accounts' => 'required',
'account_id' => 'required|numeric|belongsToUser:accounts,id', 'accounts.*' => 'array|required',
'accounts.*.account_id' => 'required|numeric|belongsToUser:accounts,id',
'accounts.*.current_amount' => ['numeric', new IsValidZeroOrMoreAmount()],
'object_group_id' => 'numeric|belongsToUser:object_groups,id', 'object_group_id' => 'numeric|belongsToUser:object_groups,id',
'object_group_title' => ['min:1', 'max:255'], 'object_group_title' => ['min:1', 'max:255'],
'target_amount' => ['required', new IsValidPositiveAmount()], 'target_amount' => ['required', new IsValidZeroOrMoreAmount()],
'start_date' => 'date|nullable', 'start_date' => 'date|nullable',
'transaction_currency_id' => 'exists:transaction_currencies,id|required_without:transaction_currency_code',
'transaction_currency_code' => 'exists:transaction_currencies,code|required_without:transaction_currency_id',
'target_date' => 'date|nullable|after:start_date', 'target_date' => 'date|nullable|after:start_date',
'notes' => 'max:65000', 'notes' => 'max:65000',
]; ];
} }
/**
* Can only store money on liabilities and asset accounts.
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
// validate start before end only if both are there.
$data = $validator->getData();
$currency = $this->getCurrencyFromData($data);
$targetAmount = (string) ($data['target_amount'] ?? '0');
$currentAmount = '0';
if (array_key_exists('accounts', $data) && is_array($data['accounts'])) {
$repository = app(AccountRepositoryInterface::class);
$types = config('firefly.piggy_bank_account_types');
foreach ($data['accounts'] as $index => $array) {
$accountId = (int) ($array['account_id'] ?? 0);
$account = $repository->find($accountId);
if (null !== $account) {
// check currency here.
$accountCurrency = $repository->getAccountCurrency($account);
$isMultiCurrency = $repository->getMetaValue($account, 'is_multi_currency');
$currentAmount = bcadd($currentAmount, (string) ($array['current_amount'] ?? '0'));
if ($accountCurrency->id !== $currency->id && 'true' !== $isMultiCurrency) {
$validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_currency'));
}
$type = $account->accountType->type;
if (!in_array($type, $types, true)) {
$validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_type'));
}
}
}
}
if (-1 === bccomp($targetAmount, $currentAmount) && 1 === bccomp($targetAmount, '0')) {
$validator->errors()->add('target_amount', trans('validation.current_amount_too_much'));
}
}
);
if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}
private function getCurrencyFromData(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;
}
}
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;
}
}
throw new FireflyException('Unexpected empty currency.');
}
} }

View File

@ -121,10 +121,10 @@ class StoreRequest extends FormRequest
$current['moment'] = $repetition['moment']; $current['moment'] = $repetition['moment'];
} }
if (array_key_exists('skip', $repetition)) { if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip']; $current['skip'] = (int) $repetition['skip'];
} }
if (array_key_exists('weekend', $repetition)) { if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend']; $current['weekend'] = (int) $repetition['weekend'];
} }
$return[] = $current; $return[] = $current;

View File

@ -101,15 +101,15 @@ class UpdateRequest extends FormRequest
} }
if (array_key_exists('moment', $repetition)) { if (array_key_exists('moment', $repetition)) {
$current['moment'] = (string)$repetition['moment']; $current['moment'] = (string) $repetition['moment'];
} }
if (array_key_exists('skip', $repetition)) { if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip']; $current['skip'] = (int) $repetition['skip'];
} }
if (array_key_exists('weekend', $repetition)) { if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend']; $current['weekend'] = (int) $repetition['weekend'];
} }
$return[] = $current; $return[] = $current;
} }

View File

@ -74,9 +74,9 @@ class StoreRequest extends FormRequest
$return[] = [ $return[] = [
'type' => $trigger['type'] ?? '', 'type' => $trigger['type'] ?? '',
'value' => $trigger['value'] ?? null, 'value' => $trigger['value'] ?? null,
'prohibited' => $this->convertBoolean((string)($trigger['prohibited'] ?? 'false')), 'prohibited' => $this->convertBoolean((string) ($trigger['prohibited'] ?? 'false')),
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')), 'active' => $this->convertBoolean((string) ($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')), 'stop_processing' => $this->convertBoolean((string) ($trigger['stop_processing'] ?? 'false')),
]; ];
} }
} }
@ -93,8 +93,8 @@ class StoreRequest extends FormRequest
$return[] = [ $return[] = [
'type' => $action['type'], 'type' => $action['type'],
'value' => $action['value'], 'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')), 'active' => $this->convertBoolean((string) ($action['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')), 'stop_processing' => $this->convertBoolean((string) ($action['stop_processing'] ?? 'false')),
]; ];
} }
} }
@ -119,7 +119,7 @@ class StoreRequest extends FormRequest
'description' => 'min:1|max:32768|nullable', 'description' => 'min:1|max:32768|nullable',
'rule_group_id' => 'belongsToUser:rule_groups|required_without:rule_group_title', 'rule_group_id' => 'belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|min:1|max:255|required_without:rule_group_id|belongsToUser:rule_groups,title', 'rule_group_title' => 'nullable|min:1|max:255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal', 'trigger' => 'required|in:store-journal,update-journal,manual-activation',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers), 'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024', 'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024',
'triggers.*.stop_processing' => [new IsBoolean()], 'triggers.*.stop_processing' => [new IsBoolean()],
@ -161,7 +161,7 @@ class StoreRequest extends FormRequest
$triggers = $data['triggers'] ?? []; $triggers = $data['triggers'] ?? [];
// need at least one trigger // need at least one trigger
if (!is_countable($triggers) || 0 === count($triggers)) { if (!is_countable($triggers) || 0 === count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger')); $validator->errors()->add('title', (string) trans('validation.at_least_one_trigger'));
} }
} }
@ -174,7 +174,7 @@ class StoreRequest extends FormRequest
$actions = $data['actions'] ?? []; $actions = $data['actions'] ?? [];
// need at least one trigger // need at least one trigger
if (!is_countable($actions) || 0 === count($actions)) { if (!is_countable($actions) || 0 === count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action')); $validator->errors()->add('title', (string) trans('validation.at_least_one_action'));
} }
} }
@ -203,7 +203,7 @@ class StoreRequest extends FormRequest
} }
} }
if (true === $allInactive) { if (true === $allInactive) {
$validator->errors()->add(sprintf('triggers.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_trigger')); $validator->errors()->add(sprintf('triggers.%d.active', $inactiveIndex), (string) trans('validation.at_least_one_active_trigger'));
} }
} }
@ -232,7 +232,7 @@ class StoreRequest extends FormRequest
} }
} }
if (true === $allInactive) { if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action')); $validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string) trans('validation.at_least_one_active_action'));
} }
} }
} }

View File

@ -49,7 +49,7 @@ class TestRequest extends FormRequest
private function getPage(): int private function getPage(): int
{ {
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page'); return 0 === (int) $this->query('page') ? 1 : (int) $this->query('page');
} }
private function getDate(string $field): ?Carbon private function getDate(string $field): ?Carbon
@ -58,7 +58,7 @@ class TestRequest extends FormRequest
if (is_array($value)) { if (is_array($value)) {
return null; return null;
} }
$value = (string)$value; $value = (string) $value;
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10)); return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10));
} }

View File

@ -52,7 +52,7 @@ class TriggerRequest extends FormRequest
if (is_array($value)) { if (is_array($value)) {
return null; return null;
} }
$value = (string)$value; $value = (string) $value;
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10)); return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10));
} }

View File

@ -109,8 +109,8 @@ class UpdateRequest extends FormRequest
$return[] = [ $return[] = [
'type' => $action['type'], 'type' => $action['type'],
'value' => $action['value'], 'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')), 'active' => $this->convertBoolean((string) ($action['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')), 'stop_processing' => $this->convertBoolean((string) ($action['stop_processing'] ?? 'false')),
]; ];
} }
} }
@ -138,7 +138,7 @@ class UpdateRequest extends FormRequest
'description' => 'min:1|max:32768|nullable', 'description' => 'min:1|max:32768|nullable',
'rule_group_id' => 'belongsToUser:rule_groups', 'rule_group_id' => 'belongsToUser:rule_groups',
'rule_group_title' => 'nullable|min:1|max:255|belongsToUser:rule_groups,title', 'rule_group_title' => 'nullable|min:1|max:255|belongsToUser:rule_groups,title',
'trigger' => 'in:store-journal,update-journal', 'trigger' => 'in:store-journal,update-journal.manual-activation',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers), 'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024', 'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024',
'triggers.*.stop_processing' => [new IsBoolean()], 'triggers.*.stop_processing' => [new IsBoolean()],
@ -181,7 +181,7 @@ class UpdateRequest extends FormRequest
$triggers = $data['triggers'] ?? null; $triggers = $data['triggers'] ?? null;
// need at least one trigger // need at least one trigger
if (is_array($triggers) && 0 === count($triggers)) { if (is_array($triggers) && 0 === count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger')); $validator->errors()->add('title', (string) trans('validation.at_least_one_trigger'));
} }
} }
@ -208,7 +208,7 @@ class UpdateRequest extends FormRequest
} }
} }
if (true === $allInactive) { if (true === $allInactive) {
$validator->errors()->add(sprintf('triggers.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_trigger')); $validator->errors()->add(sprintf('triggers.%d.active', $inactiveIndex), (string) trans('validation.at_least_one_active_trigger'));
} }
} }
@ -221,7 +221,7 @@ class UpdateRequest extends FormRequest
$actions = $data['actions'] ?? null; $actions = $data['actions'] ?? null;
// need at least one action // need at least one action
if (is_array($actions) && 0 === count($actions)) { if (is_array($actions) && 0 === count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action')); $validator->errors()->add('title', (string) trans('validation.at_least_one_action'));
} }
} }
@ -249,7 +249,7 @@ class UpdateRequest extends FormRequest
} }
} }
if (true === $allInactive) { if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action')); $validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string) trans('validation.at_least_one_active_action'));
} }
} }
} }

View File

@ -52,7 +52,7 @@ class TestRequest extends FormRequest
if (is_array($value)) { if (is_array($value)) {
return null; return null;
} }
$value = (string)$value; $value = (string) $value;
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10)); return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10));
} }

View File

@ -52,7 +52,7 @@ class TriggerRequest extends FormRequest
if (is_array($value)) { if (is_array($value)) {
return null; return null;
} }
$value = (string)$value; $value = (string) $value;
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10)); return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($value, 0, 10));
} }

View File

@ -84,73 +84,73 @@ class StoreRequest extends FormRequest
$return[] = [ $return[] = [
'type' => $this->clearString($object['type']), 'type' => $this->clearString($object['type']),
'date' => $this->dateFromValue($object['date']), 'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']), 'order' => $this->integerFromValue((string) $object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']), 'currency_id' => $this->integerFromValue((string) $object['currency_id']),
'currency_code' => $this->clearString((string)$object['currency_code']), 'currency_code' => $this->clearString((string) $object['currency_code']),
// foreign currency info: // foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']), 'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code']), 'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']),
// amount and foreign amount. Cannot be 0. // amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string)$object['amount']), 'amount' => $this->clearString((string) $object['amount']),
'foreign_amount' => $this->clearString((string)$object['foreign_amount']), 'foreign_amount' => $this->clearString((string) $object['foreign_amount']),
// description. // description.
'description' => $this->clearString($object['description']), 'description' => $this->clearString($object['description']),
// source of transaction. If everything is null, assume cash account. // source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']), 'source_id' => $this->integerFromValue((string) $object['source_id']),
'source_name' => $this->clearString((string)$object['source_name']), 'source_name' => $this->clearString((string) $object['source_name']),
'source_iban' => $this->clearIban((string)$object['source_iban']), 'source_iban' => $this->clearIban((string) $object['source_iban']),
'source_number' => $this->clearString((string)$object['source_number']), 'source_number' => $this->clearString((string) $object['source_number']),
'source_bic' => $this->clearString((string)$object['source_bic']), 'source_bic' => $this->clearString((string) $object['source_bic']),
// destination of transaction. If everything is null, assume cash account. // destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']), 'destination_id' => $this->integerFromValue((string) $object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name']), 'destination_name' => $this->clearString((string) $object['destination_name']),
'destination_iban' => $this->clearIban((string)$object['destination_iban']), 'destination_iban' => $this->clearIban((string) $object['destination_iban']),
'destination_number' => $this->clearString((string)$object['destination_number']), 'destination_number' => $this->clearString((string) $object['destination_number']),
'destination_bic' => $this->clearString((string)$object['destination_bic']), 'destination_bic' => $this->clearString((string) $object['destination_bic']),
// budget info // budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']), 'budget_id' => $this->integerFromValue((string) $object['budget_id']),
'budget_name' => $this->clearString((string)$object['budget_name']), 'budget_name' => $this->clearString((string) $object['budget_name']),
// category info // category info
'category_id' => $this->integerFromValue((string)$object['category_id']), 'category_id' => $this->integerFromValue((string) $object['category_id']),
'category_name' => $this->clearString((string)$object['category_name']), 'category_name' => $this->clearString((string) $object['category_name']),
// journal bill reference. Optional. Will only work for withdrawals // journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']), 'bill_id' => $this->integerFromValue((string) $object['bill_id']),
'bill_name' => $this->clearString((string)$object['bill_name']), 'bill_name' => $this->clearString((string) $object['bill_name']),
// piggy bank reference. Optional. Will only work for transfers // piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']), 'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name']), 'piggy_bank_name' => $this->clearString((string) $object['piggy_bank_name']),
// some other interesting properties // some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']), 'reconciled' => $this->convertBoolean((string) $object['reconciled']),
'notes' => $this->clearStringKeepNewlines((string)$object['notes']), 'notes' => $this->clearStringKeepNewlines((string) $object['notes']),
'tags' => $this->arrayFromValue($object['tags']), 'tags' => $this->arrayFromValue($object['tags']),
// all custom fields: // all custom fields:
'internal_reference' => $this->clearString((string)$object['internal_reference']), 'internal_reference' => $this->clearString((string) $object['internal_reference']),
'external_id' => $this->clearString((string)$object['external_id']), 'external_id' => $this->clearString((string) $object['external_id']),
'original_source' => sprintf('ff3-v%s', config('firefly.version')), 'original_source' => sprintf('ff3-v%s', config('firefly.version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']), 'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id']), 'bunq_payment_id' => $this->clearString((string) $object['bunq_payment_id']),
'external_url' => $this->clearString((string)$object['external_url']), 'external_url' => $this->clearString((string) $object['external_url']),
'sepa_cc' => $this->clearString((string)$object['sepa_cc']), 'sepa_cc' => $this->clearString((string) $object['sepa_cc']),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op']), 'sepa_ct_op' => $this->clearString((string) $object['sepa_ct_op']),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id']), 'sepa_ct_id' => $this->clearString((string) $object['sepa_ct_id']),
'sepa_db' => $this->clearString((string)$object['sepa_db']), 'sepa_db' => $this->clearString((string) $object['sepa_db']),
'sepa_country' => $this->clearString((string)$object['sepa_country']), 'sepa_country' => $this->clearString((string) $object['sepa_country']),
'sepa_ep' => $this->clearString((string)$object['sepa_ep']), 'sepa_ep' => $this->clearString((string) $object['sepa_ep']),
'sepa_ci' => $this->clearString((string)$object['sepa_ci']), 'sepa_ci' => $this->clearString((string) $object['sepa_ci']),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id']), 'sepa_batch_id' => $this->clearString((string) $object['sepa_batch_id']),
// custom date fields. Must be Carbon objects. Presence is optional. // custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']), 'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']), 'book_date' => $this->dateFromValue($object['book_date']),

View File

@ -137,7 +137,7 @@ class UpdateRequest extends FormRequest
{ {
foreach ($this->integerFields as $fieldName) { foreach ($this->integerFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->integerFromValue((string)$transaction[$fieldName]); $current[$fieldName] = $this->integerFromValue((string) $transaction[$fieldName]);
} }
} }
@ -152,7 +152,7 @@ class UpdateRequest extends FormRequest
{ {
foreach ($this->stringFields as $fieldName) { foreach ($this->stringFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->clearString((string)$transaction[$fieldName]); $current[$fieldName] = $this->clearString((string) $transaction[$fieldName]);
} }
} }
@ -167,7 +167,7 @@ class UpdateRequest extends FormRequest
{ {
foreach ($this->textareaFields as $fieldName) { foreach ($this->textareaFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->clearStringKeepNewlines((string)$transaction[$fieldName]); // keep newlines $current[$fieldName] = $this->clearStringKeepNewlines((string) $transaction[$fieldName]); // keep newlines
} }
} }
@ -183,8 +183,8 @@ class UpdateRequest extends FormRequest
foreach ($this->dateFields as $fieldName) { foreach ($this->dateFields as $fieldName) {
app('log')->debug(sprintf('Now at date field %s', $fieldName)); app('log')->debug(sprintf('Now at date field %s', $fieldName));
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
app('log')->debug(sprintf('New value: "%s"', (string)$transaction[$fieldName])); app('log')->debug(sprintf('New value: "%s"', (string) $transaction[$fieldName]));
$current[$fieldName] = $this->dateFromValue((string)$transaction[$fieldName]); $current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]);
} }
} }
@ -199,7 +199,7 @@ class UpdateRequest extends FormRequest
{ {
foreach ($this->booleanFields as $fieldName) { foreach ($this->booleanFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->convertBoolean((string)$transaction[$fieldName]); $current[$fieldName] = $this->convertBoolean((string) $transaction[$fieldName]);
} }
} }
@ -234,7 +234,7 @@ class UpdateRequest extends FormRequest
$current[$fieldName] = sprintf('%.12f', $value); $current[$fieldName] = sprintf('%.12f', $value);
} }
if (!is_float($value)) { if (!is_float($value)) {
$current[$fieldName] = (string)$value; $current[$fieldName] = (string) $value;
} }
} }
} }

View File

@ -98,8 +98,8 @@ class StoreRequest extends FormRequest
$journalRepos->setUser($user); $journalRepos->setUser($user);
$data = $validator->getData(); $data = $validator->getData();
$inwardId = (int)($data['inward_id'] ?? 0); $inwardId = (int) ($data['inward_id'] ?? 0);
$outwardId = (int)($data['outward_id'] ?? 0); $outwardId = (int) ($data['outward_id'] ?? 0);
$inward = $journalRepos->find($inwardId); $inward = $journalRepos->find($inwardId);
$outward = $journalRepos->find($outwardId); $outward = $journalRepos->find($outwardId);

View File

@ -100,8 +100,8 @@ class UpdateRequest extends FormRequest
$inwardId = $data['inward_id'] ?? $existing->source_id; $inwardId = $data['inward_id'] ?? $existing->source_id;
$outwardId = $data['outward_id'] ?? $existing->destination_id; $outwardId = $data['outward_id'] ?? $existing->destination_id;
$inward = $journalRepos->find((int)$inwardId); $inward = $journalRepos->find((int) $inwardId);
$outward = $journalRepos->find((int)$outwardId); $outward = $journalRepos->find((int) $outwardId);
if (null === $inward) { if (null === $inward) {
$inward = $existing->source; $inward = $existing->source;
} }

View File

@ -55,9 +55,9 @@ class CreateRequest extends FormRequest
// this is the way. // this is the way.
$return = $this->getAllData($fields); $return = $this->getAllData($fields);
$return['trigger'] = $triggers[$return['trigger']] ?? (int)$return['trigger']; $return['trigger'] = $triggers[$return['trigger']] ?? (int) $return['trigger'];
$return['response'] = $responses[$return['response']] ?? (int)$return['response']; $return['response'] = $responses[$return['response']] ?? (int) $return['response'];
$return['delivery'] = $deliveries[$return['delivery']] ?? (int)$return['delivery']; $return['delivery'] = $deliveries[$return['delivery']] ?? (int) $return['delivery'];
return $return; return $return;
} }

View File

@ -94,7 +94,7 @@ class UserUpdateRequest extends FormRequest
$isAdmin = auth()->user()->hasRole('owner'); $isAdmin = auth()->user()->hasRole('owner');
// not admin, and not own user? // not admin, and not own user?
if (auth()->check() && false === $isAdmin && $current?->id !== auth()->user()->id) { if (auth()->check() && false === $isAdmin && $current?->id !== auth()->user()->id) {
$validator->errors()->add('email', (string)trans('validation.invalid_selection')); $validator->errors()->add('email', (string) trans('validation.invalid_selection'));
} }
} }
); );

View File

@ -49,7 +49,7 @@ class PreferenceStoreRequest extends FormRequest
$array['data'] = false; $array['data'] = false;
} }
if (is_numeric($array['data'])) { if (is_numeric($array['data'])) {
$array['data'] = (float)$array['data']; // intentional float. $array['data'] = (float) $array['data']; // intentional float.
} }
return $array; return $array;

View File

@ -49,7 +49,7 @@ class PreferenceUpdateRequest extends FormRequest
$array['data'] = false; $array['data'] = false;
} }
if (is_numeric($array['data'])) { if (is_numeric($array['data'])) {
$array['data'] = (float)$array['data']; // intentional float. $array['data'] = (float) $array['data']; // intentional float.
} }
return $array; return $array;

View File

@ -40,9 +40,9 @@ use Illuminate\Support\Facades\Log;
*/ */
class AccountController extends Controller class AccountController extends Controller
{ {
private AccountRepositoryInterface $repository;
private TransactionCurrency $default;
private ExchangeRateConverter $converter; private ExchangeRateConverter $converter;
private TransactionCurrency $default;
private AccountRepositoryInterface $repository;
/** /**
* AccountController constructor. * AccountController constructor.

View File

@ -63,7 +63,7 @@ class CategoryController extends Controller
$filtered = $result->map( $filtered = $result->map(
static function (Category $item) { static function (Category $item) {
return [ return [
'id' => (string)$item->id, 'id' => (string) $item->id,
'title' => $item->name, 'title' => $item->name,
'meta' => [], 'meta' => [],
]; ];

View File

@ -45,9 +45,9 @@ class AccountController extends Controller
use CollectsAccountsFromFilter; use CollectsAccountsFromFilter;
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;
private AccountRepositoryInterface $repository;
private ChartData $chartData; private ChartData $chartData;
private TransactionCurrency $default; private TransactionCurrency $default;
private AccountRepositoryInterface $repository;
public function __construct() public function __construct()
{ {
@ -118,22 +118,21 @@ class AccountController extends Controller
'native_entries' => [], 'native_entries' => [],
]; ];
$currentStart = clone $params['start']; $currentStart = clone $params['start'];
$range = app('steam')->balanceInRange($account, $params['start'], clone $params['end'], $currency); $range = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$rangeConverted = app('steam')->balanceInRangeConverted($account, $params['start'], clone $params['end'], $this->default);
$previous = array_values($range)[0]; $previous = array_values($range)[0]['balance'];
$previousConverted = array_values($rangeConverted)[0]; $previousNative = array_values($range)[0]['native_balance'];
while ($currentStart <= $params['end']) { while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format] : $previous; $balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$balanceConverted = array_key_exists($format, $rangeConverted) ? $rangeConverted[$format] : $previousConverted; $balanceNative = array_key_exists($format, $range) ? $range[$format]['balance_native'] : $previousNative;
$previous = $balance; $previous = $balance;
$previousConverted = $balanceConverted; $previousNative = $balanceNative;
$currentStart->addDay(); $currentStart->addDay();
$currentSet['entries'][$label] = $balance; $currentSet['entries'][$label] = $balance;
$currentSet['native_entries'][$label] = $balanceConverted; $currentSet['native_entries'][$label] = $balanceNative;
} }
$this->chartData->add($currentSet); $this->chartData->add($currentSet);
} }

View File

@ -45,9 +45,10 @@ class BalanceController extends Controller
use CleansChartData; use CleansChartData;
use CollectsAccountsFromFilter; use CollectsAccountsFromFilter;
private AccountRepositoryInterface $repository;
private GroupCollectorInterface $collector;
private ChartData $chartData; private ChartData $chartData;
private GroupCollectorInterface $collector;
private AccountRepositoryInterface $repository;
// private TransactionCurrency $default; // private TransactionCurrency $default;
public function __construct() public function __construct()

View File

@ -55,8 +55,9 @@ class Controller extends BaseController
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;
protected const string CONTENT_TYPE = 'application/vnd.api+json'; protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected ParameterBag $parameters;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
protected ParameterBag $parameters;
protected bool $convertToNative = false;
public function __construct() public function __construct()
{ {
@ -81,7 +82,7 @@ class Controller extends BaseController
$bag->set('limit', 50); $bag->set('limit', 50);
try { try {
$page = (int)request()->get('page'); $page = (int) request()->get('page');
} catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) { } catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
$page = 1; $page = 1;
} }
@ -92,8 +93,8 @@ class Controller extends BaseController
if ($page < 1) { if ($page < 1) {
$page = 1; $page = 1;
} }
if ($page > (2 ^ 16)) { if ($page > 2 ** 16) {
$page = (2 ^ 16); $page = 2 ** 16;
} }
$bag->set('page', $page); $bag->set('page', $page);
@ -111,10 +112,10 @@ class Controller extends BaseController
} }
if (null !== $date) { if (null !== $date) {
try { try {
$obj = Carbon::parse((string)$date, config('app.timezone')); $obj = Carbon::parse((string) $date, config('app.timezone'));
} catch (InvalidDateException|InvalidFormatException $e) { } catch (InvalidDateException|InvalidFormatException $e) {
// don't care // don't care
app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr((string)$date, 0, 20), $e->getMessage())); app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr((string) $date, 0, 20), $e->getMessage()));
} }
// out of range? set to null. // out of range? set to null.
if (null !== $obj && ($obj->year <= 1900 || $obj->year > 2099)) { if (null !== $obj && ($obj->year <= 1900 || $obj->year > 2099)) {
@ -138,11 +139,11 @@ class Controller extends BaseController
$value = null; $value = null;
} }
if (null !== $value) { if (null !== $value) {
$bag->set($integer, (int)$value); $bag->set($integer, (int) $value);
} }
if (null === $value && 'limit' === $integer && auth()->check()) { if (null === $value && 'limit' === $integer && auth()->check()) {
// set default for user: // set default for user:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; $pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$bag->set($integer, $pageSize); $bag->set($integer, $pageSize);
} }
} }

View File

@ -1,112 +0,0 @@
<?php
/*
* AccountController.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\Api\V2\Controllers\JsonApi;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\JsonApi\V2\Accounts\AccountCollectionQuery;
use FireflyIII\JsonApi\V2\Accounts\AccountSchema;
use FireflyIII\JsonApi\V2\Accounts\AccountSingleQuery;
use FireflyIII\Models\Account;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Core\Responses\DataResponse;
use LaravelJsonApi\Laravel\Http\Controllers\Actions;
/**
* Class AccountController
*
* This class handles api/v2 requests for accounts.
* Most stuff is default stuff.
*/
class AccountController extends Controller
{
use Actions\AttachRelationship;
use Actions\Destroy;
use Actions\DetachRelationship;
use Actions\FetchMany;
// use Actions\FetchOne;
use Actions\FetchRelated;
use Actions\FetchRelationship;
use Actions\Store;
use Actions\Update;
use Actions\UpdateRelationship;
/**
* Fetch zero to many JSON API resources.
*
* @return Responsable|Response
*/
public function index(AccountSchema $schema, AccountCollectionQuery $request)
{
Log::debug(__METHOD__);
$models = $schema
->repository()
->queryAll()
->withRequest($request)
->get()
;
// do something custom...
return new DataResponse($models);
}
/**
* Fetch zero to one JSON API resource by id.
*
* @return Responsable|Response
*/
public function show(AccountSchema $schema, AccountSingleQuery $request, Account $account)
{
Log::debug(__METHOD__);
$model = $schema->repository()
->queryOne($account)
->withRequest($request)
->first()
;
Log::debug(sprintf('%s again!', __METHOD__));
// do something custom...
return new DataResponse($model);
}
// public function readAccountBalances(AnonymousQuery $query, AccountBalanceSchema $schema, Account $account): Responsable
// {
// $schema = JsonApi::server()->schemas()->schemaFor('account-balances');
//
// $models = $schema
// ->repository()
// ->queryAll()
// ->withRequest($query)
// ->withAccount($account)
// ->get()
// ;
//
// return DataResponse::make($models);
// }
}

View File

@ -36,9 +36,8 @@ use Illuminate\Support\Facades\Log;
class IndexController extends Controller class IndexController extends Controller
{ {
public const string RESOURCE_KEY = 'accounts'; public const string RESOURCE_KEY = 'accounts';
private AccountRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS]; protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS];
private AccountRepositoryInterface $repository;
/** /**
* AccountController constructor. * AccountController constructor.

View File

@ -39,9 +39,8 @@ use Illuminate\Http\JsonResponse;
class ShowController extends Controller class ShowController extends Controller
{ {
public const string RESOURCE_KEY = 'accounts'; public const string RESOURCE_KEY = 'accounts';
private AccountRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS]; protected array $acceptedRoles = [UserRoleEnum::READ_ONLY, UserRoleEnum::MANAGE_TRANSACTIONS];
private AccountRepositoryInterface $repository;
/** /**
* AccountController constructor. * AccountController constructor.

View File

@ -0,0 +1,67 @@
<?php
/*
* DestroyController.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\Api\V2\Controllers\Model\ExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\ExchangeRate\DestroyRequest;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class DestroyController extends Controller
{
use ValidatesUserGroupTrait;
public const string RESOURCE_KEY = 'exchange-rates';
private ExchangeRateRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(ExchangeRateRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
);
}
public function destroy(DestroyRequest $request, TransactionCurrency $from, TransactionCurrency $to): JsonResponse
{
$date = $request->getDate();
$rate = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null === $rate) {
throw new NotFoundHttpException();
}
$this->repository->deleteRate($rate);
return response()->json([], 204);
}
}

View File

@ -0,0 +1,75 @@
<?php
/*
* ShowController.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\Api\V2\Controllers\Model\ExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* Class ShowController
*/
class IndexController extends Controller
{
use ValidatesUserGroupTrait;
public const string RESOURCE_KEY = 'exchange-rates';
private ExchangeRateRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(ExchangeRateRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
);
}
public function index(): JsonResponse
{
$piggies = $this->repository->getAll();
$pageSize = $this->parameters->get('limit');
$count = $piggies->count();
$piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));
var_dump('here we are');
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@ -0,0 +1,76 @@
<?php
/*
* ShowController.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\Api\V2\Controllers\Model\ExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\ExchangeRateTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* Class ShowController
*/
class ShowController extends Controller
{
use ValidatesUserGroupTrait;
public const string RESOURCE_KEY = 'exchange-rates';
private ExchangeRateRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(ExchangeRateRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
);
}
public function show(TransactionCurrency $from, TransactionCurrency $to): JsonResponse
{
$pageSize = $this->parameters->get('limit');
$page = $this->parameters->get('page');
$rates = $this->repository->getRates($from, $to);
$count = $rates->count();
$rates = $rates->slice(($page - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($rates, $count, $pageSize, $page);
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
* DestroyController.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\Api\V2\Controllers\Model\ExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\ExchangeRate\StoreRequest;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\ExchangeRateTransformer;
use Illuminate\Http\JsonResponse;
class StoreController extends Controller
{
use ValidatesUserGroupTrait;
public const string RESOURCE_KEY = 'exchange-rates';
private ExchangeRateRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(ExchangeRateRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
);
}
public function store(StoreRequest $request): JsonResponse
{
$date = $request->getDate();
$rate = $request->getRate();
$from = $request->getFromCurrency();
$to = $request->getToCurrency();
// already has rate?
$object = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null !== $object) {
// just update it, no matter.
$rate = $this->repository->updateExchangeRate($object, $rate, $date);
}
if (null === $object) {
// store new
$rate = $this->repository->storeExchangeRate($from, $to, $rate, $date);
}
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $rate, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@ -0,0 +1,69 @@
<?php
/*
* DestroyController.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\Api\V2\Controllers\Model\ExchangeRate;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\ExchangeRate\UpdateRequest;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\ExchangeRateTransformer;
use Illuminate\Http\JsonResponse;
class UpdateController extends Controller
{
use ValidatesUserGroupTrait;
public const string RESOURCE_KEY = 'exchange-rates';
private ExchangeRateRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(ExchangeRateRepositoryInterface::class);
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
);
}
public function update(UpdateRequest $request, CurrencyExchangeRate $exchangeRate): JsonResponse
{
$date = $request->getDate();
$rate = $request->getRate();
$exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date);
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@ -0,0 +1,83 @@
<?php
/*
* IndexController.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\Api\V2\Controllers\Model\TransactionCurrency;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\TransactionCurrency\IndexRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\V2\CurrencyTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
class IndexController extends Controller
{
public const string RESOURCE_KEY = 'transaction-currencies';
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
private CurrencyRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(CurrencyRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
return $next($request);
}
);
}
public function index(IndexRequest $request): JsonResponse
{
$settings = $request->getAll();
if (true === $settings['enabled']) {
$currencies = $this->repository->get();
}
if (true !== $settings['enabled']) {
$currencies = $this->repository->getAll();
}
$pageSize = $this->parameters->get('limit');
$count = $currencies->count();
// depending on the sort parameters, this list must not be split, because the
// order is calculated in the account transformer and by that time it's too late.
$accounts = $currencies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$transformer = new CurrencyTransformer();
$this->parameters->set('pageSize', $pageSize);
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@ -0,0 +1,80 @@
<?php
/*
* ShowController.php
* Copyright (c) 2021 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\Api\V2\Controllers\Model\TransactionCurrency;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\V2\CurrencyTransformer;
use Illuminate\Http\JsonResponse;
/**
* Class ShowController
*/
class ShowController extends Controller
{
public const string RESOURCE_KEY = 'transaction-currencies';
private CurrencyRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(CurrencyRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
return $next($request);
}
);
}
public function show(TransactionCurrency $currency): JsonResponse
{
$groups = $currency->userGroups()->where('user_groups.id', $this->repository->getUserGroup()->id)->get();
$enabled = $groups->count() > 0;
$default = false;
/** @var UserGroup $group */
foreach ($groups as $group) {
$default = 1 === $group->pivot->group_default;
}
$currency->userGroupEnabled = $enabled;
$currency->userGroupDefault = $default;
$transformer = new CurrencyTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $currency, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@ -179,7 +179,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('bills-paid-in-%s', $info['currency_code']), 'key' => sprintf('bills-paid-in-%s', $info['currency_code']),
'value' => $amount, 'value' => $amount,
'currency_id' => (string)$info['currency_id'], 'currency_id' => (string) $info['currency_id'],
'currency_code' => $info['currency_code'], 'currency_code' => $info['currency_code'],
'currency_symbol' => $info['currency_symbol'], 'currency_symbol' => $info['currency_symbol'],
'currency_decimal_places' => $info['currency_decimal_places'], 'currency_decimal_places' => $info['currency_decimal_places'],
@ -187,7 +187,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'bills-paid-in-native', 'key' => 'bills-paid-in-native',
'value' => $nativeAmount, 'value' => $nativeAmount,
'currency_id' => (string)$info['native_currency_id'], 'currency_id' => (string) $info['native_currency_id'],
'currency_code' => $info['native_currency_code'], 'currency_code' => $info['native_currency_code'],
'currency_symbol' => $info['native_currency_symbol'], 'currency_symbol' => $info['native_currency_symbol'],
'currency_decimal_places' => $info['native_currency_decimal_places'], 'currency_decimal_places' => $info['native_currency_decimal_places'],
@ -203,7 +203,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']), 'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']),
'value' => $amount, 'value' => $amount,
'currency_id' => (string)$info['currency_id'], 'currency_id' => (string) $info['currency_id'],
'currency_code' => $info['currency_code'], 'currency_code' => $info['currency_code'],
'currency_symbol' => $info['currency_symbol'], 'currency_symbol' => $info['currency_symbol'],
'currency_decimal_places' => $info['currency_decimal_places'], 'currency_decimal_places' => $info['currency_decimal_places'],
@ -211,7 +211,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'bills-unpaid-in-native', 'key' => 'bills-unpaid-in-native',
'value' => $nativeAmount, 'value' => $nativeAmount,
'currency_id' => (string)$info['native_currency_id'], 'currency_id' => (string) $info['native_currency_id'],
'currency_code' => $info['native_currency_code'], 'currency_code' => $info['native_currency_code'],
'currency_symbol' => $info['native_currency_symbol'], 'currency_symbol' => $info['native_currency_symbol'],
'currency_decimal_places' => $info['native_currency_decimal_places'], 'currency_decimal_places' => $info['native_currency_decimal_places'],
@ -241,7 +241,7 @@ class BasicController extends Controller
$nativeLeft = [ $nativeLeft = [
'key' => 'left-to-spend-in-native', 'key' => 'left-to-spend-in-native',
'value' => '0', 'value' => '0',
'currency_id' => (string)$default->id, 'currency_id' => (string) $default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places, 'currency_decimal_places' => $default->decimal_places,
@ -249,7 +249,7 @@ class BasicController extends Controller
$nativePerDay = [ $nativePerDay = [
'key' => 'left-per-day-to-spend-in-native', 'key' => 'left-per-day-to-spend-in-native',
'value' => '0', 'value' => '0',
'currency_id' => (string)$default->id, 'currency_id' => (string) $default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places, 'currency_decimal_places' => $default->decimal_places,
@ -276,7 +276,7 @@ class BasicController extends Controller
$currencies[$currencyId] = $currency; $currencies[$currencyId] = $currency;
$amount = app('steam')->negative($journal['amount']); $amount = app('steam')->negative($journal['amount']);
$amountNative = $converter->convert($default, $currency, $start, $amount); $amountNative = $converter->convert($default, $currency, $start, $amount);
if ((int)$journal['foreign_currency_id'] === $default->id) { if ((int) $journal['foreign_currency_id'] === $default->id) {
$amountNative = $journal['foreign_amount']; $amountNative = $journal['foreign_amount'];
} }
$spent = bcadd($spent, $amount); $spent = bcadd($spent, $amount);
@ -296,24 +296,24 @@ class BasicController extends Controller
app('log')->debug(sprintf('Amount left is %s', $left)); app('log')->debug(sprintf('Amount left is %s', $left));
// how much left per day? // how much left per day?
$days = (int)$today->diffInDays($end, true) + 1; $days = (int) $today->diffInDays($end, true) + 1;
$perDay = '0'; $perDay = '0';
$perDayNative = '0'; $perDayNative = '0';
if (0 !== $days && bccomp($left, '0') > -1) { if (0 !== $days && bccomp($left, '0') > -1) {
$perDay = bcdiv($left, (string)$days); $perDay = bcdiv($left, (string) $days);
} }
if (0 !== $days && bccomp($leftNative, '0') > -1) { if (0 !== $days && bccomp($leftNative, '0') > -1) {
$perDayNative = bcdiv($leftNative, (string)$days); $perDayNative = bcdiv($leftNative, (string) $days);
} }
// left // left
$return[] = [ $return[] = [
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'value' => $left, 'value' => $left,
'currency_id' => (string)$row['currency_id'], 'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => (int)$row['currency_decimal_places'], 'currency_decimal_places' => (int) $row['currency_decimal_places'],
]; ];
// left (native) // left (native)
$nativeLeft['value'] = $leftNative; $nativeLeft['value'] = $leftNative;
@ -322,10 +322,10 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']),
'value' => $perDay, 'value' => $perDay,
'currency_id' => (string)$row['currency_id'], 'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => (int)$row['currency_decimal_places'], 'currency_decimal_places' => (int) $row['currency_decimal_places'],
]; ];
// left per day (native) // left per day (native)
@ -371,7 +371,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'net-worth-in-native', 'key' => 'net-worth-in-native',
'value' => $netWorthSet['native']['balance'], 'value' => $netWorthSet['native']['balance'],
'currency_id' => (string)$netWorthSet['native']['currency_id'], 'currency_id' => (string) $netWorthSet['native']['currency_id'],
'currency_code' => $netWorthSet['native']['currency_code'], 'currency_code' => $netWorthSet['native']['currency_code'],
'currency_symbol' => $netWorthSet['native']['currency_symbol'], 'currency_symbol' => $netWorthSet['native']['currency_symbol'],
'currency_decimal_places' => $netWorthSet['native']['currency_decimal_places'], 'currency_decimal_places' => $netWorthSet['native']['currency_decimal_places'],
@ -383,7 +383,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('net-worth-in-%s', $data['currency_code']), 'key' => sprintf('net-worth-in-%s', $data['currency_code']),
'value' => $data['balance'], 'value' => $data['balance'],
'currency_id' => (string)$data['currency_id'], 'currency_id' => (string) $data['currency_id'],
'currency_code' => $data['currency_code'], 'currency_code' => $data['currency_code'],
'currency_symbol' => $data['currency_symbol'], 'currency_symbol' => $data['currency_symbol'],
'currency_decimal_places' => $data['currency_decimal_places'], 'currency_decimal_places' => $data['currency_decimal_places'],

View File

@ -73,6 +73,16 @@ class AutocompleteRequest extends FormRequest
return $array; return $array;
} }
private function getAccountTypeParameter(array $types): array
{
$return = [];
foreach ($types as $type) {
$return = array_merge($return, $this->mapAccountTypes($type));
}
return array_unique($return);
}
public function rules(): array public function rules(): array
{ {
$valid = array_keys($this->types); $valid = array_keys($this->types);
@ -86,14 +96,4 @@ class AutocompleteRequest extends FormRequest
'transaction_types' => 'nullable|in:todo', 'transaction_types' => 'nullable|in:todo',
]; ];
} }
private function getAccountTypeParameter(array $types): array
{
$return = [];
foreach ($types as $type) {
$return = array_merge($return, $this->mapAccountTypes($type));
}
return array_unique($return);
}
} }

View File

@ -40,6 +40,7 @@ class BalanceChartRequest extends FormRequest
use ChecksLogin; use ChecksLogin;
use ConvertsDataTypes; use ConvertsDataTypes;
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/** /**

View File

@ -1,7 +1,7 @@
<?php <?php
/* /*
* AccountBalanceRepository.php * DestroyRequest.php
* Copyright (c) 2024 james@firefly-iii.org. * Copyright (c) 2024 james@firefly-iii.org.
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
@ -22,25 +22,30 @@
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\AccountBalances; namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
use FireflyIII\Entities\AccountBalance; use Carbon\Carbon;
use LaravelJsonApi\Contracts\Store\QueriesAll; use FireflyIII\Support\Request\ChecksLogin;
use LaravelJsonApi\NonEloquent\AbstractRepository; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
class AccountBalanceRepository extends AbstractRepository implements QueriesAll class DestroyRequest extends FormRequest
{ {
#[\Override] use ChecksLogin;
public function find(string $resourceId): ?object use ConvertsDataTypes;
public function getDate(): Carbon
{ {
return AccountBalance::fromArray(); return $this->getCarbonDate('date');
} }
public function queryAll(): Capabilities\AccountBalanceQuery /**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{ {
return Capabilities\AccountBalanceQuery::make() return [
->withServer($this->server) 'date' => 'required|date|after:1900-01-01|before:2099-12-31',
->withSchema($this->schema) ];
;
} }
} }

View File

@ -0,0 +1,70 @@
<?php
/*
* DestroyRequest.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\Api\V2\Request\Model\ExchangeRate;
use Carbon\Carbon;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
class StoreRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
public function getDate(): ?Carbon
{
return $this->getCarbonDate('date');
}
public function getRate(): string
{
return (string) $this->get('rate');
}
public function getFromCurrency(): TransactionCurrency
{
return TransactionCurrency::where('code', $this->get('from'))->first();
}
public function getToCurrency(): TransactionCurrency
{
return TransactionCurrency::where('code', $this->get('to'))->first();
}
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31',
'rate' => 'required|numeric|gt:0',
'from' => 'required|exists:transaction_currencies,code',
'to' => 'required|exists:transaction_currencies,code',
];
}
}

View File

@ -1,7 +1,7 @@
<?php <?php
/* /*
* AccountBalanceQuery.php * DestroyRequest.php
* Copyright (c) 2024 james@firefly-iii.org. * Copyright (c) 2024 james@firefly-iii.org.
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
@ -22,38 +22,36 @@
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\AccountBalances\Capabilities; namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
use FireflyIII\Entities\AccountBalance; use Carbon\Carbon;
use FireflyIII\Models\Account; use FireflyIII\Support\Request\ChecksLogin;
use LaravelJsonApi\NonEloquent\Capabilities\QueryAll; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
class AccountBalanceQuery extends QueryAll class UpdateRequest extends FormRequest
{ {
private Account $account; use ChecksLogin;
use ConvertsDataTypes;
public function getDate(): ?Carbon
{
return $this->getCarbonDate('date');
}
public function getRate(): string
{
return (string) $this->get('rate');
}
/** /**
* QuerySites constructor. * The rules that the incoming request must be matched against.
*/ */
public function __construct() public function rules(): array
{
parent::__construct();
}
public function get(): iterable
{ {
return [ return [
AccountBalance::fromArray(), 'date' => 'date|after:1900-01-01|before:2099-12-31',
AccountBalance::fromArray(), 'rate' => 'required|numeric|gt:0',
AccountBalance::fromArray(),
AccountBalance::fromArray(),
]; ];
} }
public function withAccount(Account $account): self
{
$this->account = $account;
return $this;
}
} }

View File

@ -87,7 +87,7 @@ class InfiniteListRequest extends FormRequest
public function getAccountTypes(): array public function getAccountTypes(): array
{ {
$type = (string)$this->get('type', 'default'); $type = (string) $this->get('type', 'default');
return $this->mapAccountTypes($type); return $this->mapAccountTypes($type);
} }
@ -101,7 +101,7 @@ class InfiniteListRequest extends FormRequest
public function getTransactionTypes(): array public function getTransactionTypes(): array
{ {
$type = (string)$this->get('type', 'default'); $type = (string) $this->get('type', 'default');
return $this->mapTransactionTypes($type); return $this->mapTransactionTypes($type);
} }

View File

@ -76,7 +76,7 @@ class ListRequest extends FormRequest
public function getTransactionTypes(): array public function getTransactionTypes(): array
{ {
$type = (string)$this->get('type', 'default'); $type = (string) $this->get('type', 'default');
return $this->mapTransactionTypes($type); return $this->mapTransactionTypes($type);
} }

View File

@ -94,73 +94,73 @@ class StoreRequest extends FormRequest
$result = [ $result = [
'type' => $this->clearString($object['type']), 'type' => $this->clearString($object['type']),
'date' => $this->dateFromValue($object['date']), 'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']), 'order' => $this->integerFromValue((string) $object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']), 'currency_id' => $this->integerFromValue((string) $object['currency_id']),
'currency_code' => $this->clearString((string)$object['currency_code']), 'currency_code' => $this->clearString((string) $object['currency_code']),
// foreign currency info: // foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']), 'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code']), 'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']),
// amount and foreign amount. Cannot be 0. // amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string)$object['amount']), 'amount' => $this->clearString((string) $object['amount']),
'foreign_amount' => $this->clearString((string)$object['foreign_amount']), 'foreign_amount' => $this->clearString((string) $object['foreign_amount']),
// description. // description.
'description' => $this->clearString($object['description']), 'description' => $this->clearString($object['description']),
// source of transaction. If everything is null, assume cash account. // source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']), 'source_id' => $this->integerFromValue((string) $object['source_id']),
'source_name' => $this->clearString((string)$object['source_name']), 'source_name' => $this->clearString((string) $object['source_name']),
'source_iban' => $this->clearString((string)$object['source_iban']), 'source_iban' => $this->clearString((string) $object['source_iban']),
'source_number' => $this->clearString((string)$object['source_number']), 'source_number' => $this->clearString((string) $object['source_number']),
'source_bic' => $this->clearString((string)$object['source_bic']), 'source_bic' => $this->clearString((string) $object['source_bic']),
// destination of transaction. If everything is null, assume cash account. // destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']), 'destination_id' => $this->integerFromValue((string) $object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name']), 'destination_name' => $this->clearString((string) $object['destination_name']),
'destination_iban' => $this->clearString((string)$object['destination_iban']), 'destination_iban' => $this->clearString((string) $object['destination_iban']),
'destination_number' => $this->clearString((string)$object['destination_number']), 'destination_number' => $this->clearString((string) $object['destination_number']),
'destination_bic' => $this->clearString((string)$object['destination_bic']), 'destination_bic' => $this->clearString((string) $object['destination_bic']),
// budget info // budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']), 'budget_id' => $this->integerFromValue((string) $object['budget_id']),
'budget_name' => $this->clearString((string)$object['budget_name']), 'budget_name' => $this->clearString((string) $object['budget_name']),
// category info // category info
'category_id' => $this->integerFromValue((string)$object['category_id']), 'category_id' => $this->integerFromValue((string) $object['category_id']),
'category_name' => $this->clearString((string)$object['category_name']), 'category_name' => $this->clearString((string) $object['category_name']),
// journal bill reference. Optional. Will only work for withdrawals // journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']), 'bill_id' => $this->integerFromValue((string) $object['bill_id']),
'bill_name' => $this->clearString((string)$object['bill_name']), 'bill_name' => $this->clearString((string) $object['bill_name']),
// piggy bank reference. Optional. Will only work for transfers // piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']), 'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name']), 'piggy_bank_name' => $this->clearString((string) $object['piggy_bank_name']),
// some other interesting properties // some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']), 'reconciled' => $this->convertBoolean((string) $object['reconciled']),
'notes' => $this->clearStringKeepNewlines((string)$object['notes']), 'notes' => $this->clearStringKeepNewlines((string) $object['notes']),
'tags' => $this->arrayFromValue($object['tags']), 'tags' => $this->arrayFromValue($object['tags']),
// all custom fields: // all custom fields:
'internal_reference' => $this->clearString((string)$object['internal_reference']), 'internal_reference' => $this->clearString((string) $object['internal_reference']),
'external_id' => $this->clearString((string)$object['external_id']), 'external_id' => $this->clearString((string) $object['external_id']),
'original_source' => sprintf('ff3-v%s', config('firefly.version')), 'original_source' => sprintf('ff3-v%s', config('firefly.version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']), 'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id']), 'bunq_payment_id' => $this->clearString((string) $object['bunq_payment_id']),
'external_url' => $this->clearString((string)$object['external_url']), 'external_url' => $this->clearString((string) $object['external_url']),
'sepa_cc' => $this->clearString((string)$object['sepa_cc']), 'sepa_cc' => $this->clearString((string) $object['sepa_cc']),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op']), 'sepa_ct_op' => $this->clearString((string) $object['sepa_ct_op']),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id']), 'sepa_ct_id' => $this->clearString((string) $object['sepa_ct_id']),
'sepa_db' => $this->clearString((string)$object['sepa_db']), 'sepa_db' => $this->clearString((string) $object['sepa_db']),
'sepa_country' => $this->clearString((string)$object['sepa_country']), 'sepa_country' => $this->clearString((string) $object['sepa_country']),
'sepa_ep' => $this->clearString((string)$object['sepa_ep']), 'sepa_ep' => $this->clearString((string) $object['sepa_ep']),
'sepa_ci' => $this->clearString((string)$object['sepa_ci']), 'sepa_ci' => $this->clearString((string) $object['sepa_ci']),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id']), 'sepa_batch_id' => $this->clearString((string) $object['sepa_batch_id']),
// custom date fields. Must be Carbon objects. Presence is optional. // custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']), 'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']), 'book_date' => $this->dateFromValue($object['book_date']),

View File

@ -139,7 +139,7 @@ class UpdateRequest extends Request
{ {
foreach ($this->integerFields as $fieldName) { foreach ($this->integerFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->integerFromValue((string)$transaction[$fieldName]); $current[$fieldName] = $this->integerFromValue((string) $transaction[$fieldName]);
} }
} }
@ -154,7 +154,7 @@ class UpdateRequest extends Request
{ {
foreach ($this->stringFields as $fieldName) { foreach ($this->stringFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->clearString((string)$transaction[$fieldName]); $current[$fieldName] = $this->clearString((string) $transaction[$fieldName]);
} }
} }
@ -169,7 +169,7 @@ class UpdateRequest extends Request
{ {
foreach ($this->textareaFields as $fieldName) { foreach ($this->textareaFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->clearStringKeepNewlines((string)$transaction[$fieldName]); // keep newlines $current[$fieldName] = $this->clearStringKeepNewlines((string) $transaction[$fieldName]); // keep newlines
} }
} }
@ -185,8 +185,8 @@ class UpdateRequest extends Request
foreach ($this->dateFields as $fieldName) { foreach ($this->dateFields as $fieldName) {
app('log')->debug(sprintf('Now at date field %s', $fieldName)); app('log')->debug(sprintf('Now at date field %s', $fieldName));
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
app('log')->debug(sprintf('New value: "%s"', (string)$transaction[$fieldName])); app('log')->debug(sprintf('New value: "%s"', (string) $transaction[$fieldName]));
$current[$fieldName] = $this->dateFromValue((string)$transaction[$fieldName]); $current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]);
} }
} }
@ -201,7 +201,7 @@ class UpdateRequest extends Request
{ {
foreach ($this->booleanFields as $fieldName) { foreach ($this->booleanFields as $fieldName) {
if (array_key_exists($fieldName, $transaction)) { if (array_key_exists($fieldName, $transaction)) {
$current[$fieldName] = $this->convertBoolean((string)$transaction[$fieldName]); $current[$fieldName] = $this->convertBoolean((string) $transaction[$fieldName]);
} }
} }
@ -236,7 +236,7 @@ class UpdateRequest extends Request
$current[$fieldName] = sprintf('%.12f', $value); $current[$fieldName] = sprintf('%.12f', $value);
} }
if (!is_float($value)) { if (!is_float($value)) {
$current[$fieldName] = (string)$value; $current[$fieldName] = (string) $value;
} }
} }
} }

View File

@ -0,0 +1,64 @@
<?php
/*
* IndexRequest.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\Api\V2\Request\Model\TransactionCurrency;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\Support\Request\GetFilterInstructions;
use FireflyIII\Support\Request\GetSortInstructions;
use Illuminate\Foundation\Http\FormRequest;
/**
* Class IndexRequest
*
* Lots of code stolen from the SingleDateRequest.
*/
class IndexRequest extends FormRequest
{
use AccountFilter;
use ChecksLogin;
use ConvertsDataTypes;
use GetFilterInstructions;
use GetSortInstructions;
public function getAll(): array
{
return [
'enabled' => $this->convertBoolean($this->get('enabled')),
];
}
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'enabled' => 'nullable|boolean',
];
}
}

View File

@ -52,7 +52,7 @@ class AutoSum
$amount = $getSum($object); $amount = $getSum($object);
$return[$currency->id] ??= [ $return[$currency->id] ??= [
'id' => (string)$currency->id, 'id' => (string) $currency->id,
'name' => $currency->name, 'name' => $currency->name,
'symbol' => $currency->symbol, 'symbol' => $currency->symbol,
'code' => $currency->code, 'code' => $currency->code,

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