Compare commits

..

17 Commits

Author SHA1 Message Date
github-actions
b58d809063 Auto commit for release 'develop' on 2024-12-31 2024-12-31 08:09:51 +01:00
James Cole
9e34314dbc Fix various issues with new features, nullpointers and missing checks. 2024-12-31 08:05:25 +01:00
github-actions
e4aa218b5f Auto commit for release 'v6.2.0-alpha.1' on 2024-12-30 2024-12-30 17:09:40 +01:00
github-actions
31722477d4 Merge branch 'develop' 2024-12-30 16:07:29 +00:00
github-actions
ec82105433 Auto commit for release 'develop' on 2024-12-30 2024-12-30 15:35:26 +01:00
James Cole
146e164f04 Back to 8. 2024-12-30 15:31:27 +01:00
James Cole
7d37c93988 Expand workflow. 2024-12-30 15:25:39 +01:00
James Cole
73dffacd9a Expand to support alpha and beta versions. 2024-12-30 12:23:50 +01:00
James Cole
d37304fa68 Fix available budgets. 2024-12-30 12:22:39 +01:00
James Cole
62f4da6063 Update available budgets code. 2024-12-30 10:51:34 +01:00
James Cole
760da08ab7 Update exchange rates. 2024-12-30 07:36:22 +01:00
James Cole
e68c4d4408 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2024-12-30 07:36:12 +01:00
James Cole
46a200aa1f Fix broken variable. 2024-12-30 07:30:23 +01:00
James Cole
c422039335 Merge pull request #9589 from tasnim0tantawi/autocomplete-test
Autocomplete test - CurrencyControllerTest & ObjectGroupControllerTest
2024-12-30 07:18:05 +01:00
TasneemTantawy
5971d155ef fixed create authenticated user 2024-12-23 09:37:06 +03:00
TasneemTantawy
9e373a9b0d object group controller test 2024-12-22 16:29:56 +03:00
TasneemTantawy
4fb61646b4 currency controller test 2024-12-22 15:54:18 +03:00
50 changed files with 618 additions and 202 deletions

View File

@@ -168,7 +168,7 @@ jobs:
# if this is a develop build, slightly different variable names.
if [[ "develop" == "$version" ]]; then
[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
#[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
releaseName=$version-$(date +'%Y%m%d')
originalName=$releaseName
zipName=FireflyIII-develop.zip
@@ -177,7 +177,7 @@ jobs:
# if this is a branch build, also slightly different variable names.
if [[ "$version" == branch* ]]; then
[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
#[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
# branch builds overrule develop
releaseName=$version-$(date +'%Y%m%d')
originalName=$releaseName
@@ -229,7 +229,7 @@ jobs:
# describe the development release.
if [[ "develop" == "$version" ]]; then
echo 'Develop release.'
rm output.txt
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt
@@ -244,7 +244,7 @@ jobs:
# describe a branch release
if [[ "$version" == branch* ]]; then
echo 'Branch release.'
rm output.txt
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Irregular BRANCH release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
@@ -257,9 +257,45 @@ jobs:
echo ":warning: Please be careful with this branch pre-release, as it may not work as expected." >> output.txt
fi
# describe the main release
if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]]; then
sudo chown -R runner:docker output.txt
if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then
echo 'Main release.'
sudo chown -R runner:docker output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
fi
# describe alpha release
if [[ "$version" == *alpha* ]]; then
echo 'ALPHA release.'
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Very early ALPHA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo '' >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
fi
# describe beta release
if [[ "$version" == *beta* ]]; then
echo 'BETA release.'
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Very early BETA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo '' >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
@@ -336,12 +372,12 @@ jobs:
gh release upload $releaseName HEAD.txt
# remove all temporary files
rm output.txt
rm HEAD.txt
rm $zipName
rm $zipName.sha256
rm $tarName
rm $tarName.sha256
rm -f output.txt
rm -f HEAD.txt
rm -f $zipName
rm -f $zipName.sha256
rm -f $tarName
rm -f $tarName.sha256
# merge main back into develop
git checkout develop

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.
## 2024
- TasneemTantawy
- Antônio Franco
- yparitcher
- Jhon Pedroza

View File

@@ -29,7 +29,6 @@ use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\AccountFilter;
@@ -86,7 +85,7 @@ class AccountController extends Controller
foreach ($result as $account) {
$nameWithBalance = $account->name;
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = Steam::finalAccountBalance($account, $date);
$key = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
@@ -116,7 +115,7 @@ class AccountController extends Controller
usort(
$return,
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);
$posB = (int) array_search($right['type'], $order, true);

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Chart;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Support\Http\Api\ParsesQueryFilters;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
@@ -40,7 +39,6 @@ class ChartRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
use ParsesQueryFilters;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];

View File

@@ -143,6 +143,7 @@ class BudgetLimitHandler
);
$availableBudget->save();
Log::debug(sprintf('ID of new AB is #%d', $availableBudget->id));
$this->calculateAmount($availableBudget);
}
}

View File

@@ -33,7 +33,7 @@ class AvailableBudgetObserver
{
public function created(AvailableBudget $availableBudget): void
{
Log::debug('Observe "created" of an available budget.');
// Log::debug('Observe "created" of an available budget.');
$this->updateNativeAmount($availableBudget);
}
@@ -46,7 +46,7 @@ class AvailableBudgetObserver
private function updateNativeAmount(AvailableBudget $availableBudget): void
{
if (!Amount::convertToNative($availableBudget->user)) {
Log::debug('Do not update native available amount of the available budget.');
// Log::debug('Do not update native available amount of the available budget.');
return;
}

View File

@@ -46,7 +46,7 @@ class BudgetLimitObserver
private function updateNativeAmount(BudgetLimit $budgetLimit): void
{
if (!Amount::convertToNative($budgetLimit->budget->user)) {
Log::debug('Do not update native amount of the budget limit.');
// Log::debug('Do not update native amount of the budget limit.');
return;
}

View File

@@ -76,7 +76,6 @@ class CreateController extends Controller
*/
public function create(Request $request, string $objectType)
{
$defaultCurrency = app('amount')->getDefaultCurrency();
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$subTitle = (string) trans(sprintf('firefly.make_new_%s_account', $objectType));
$roles = $this->getRoles();
@@ -106,7 +105,7 @@ class CreateController extends Controller
$request->session()->flash(
'preFilled',
[
'currency_id' => $defaultCurrency->id,
'currency_id' => $this->defaultCurrency->id,
'include_net_worth' => $hasOldInput ? (bool) $request->old('include_net_worth') : true,
]
);

View File

@@ -124,7 +124,7 @@ class EditController extends Controller
$openingBalanceAmount = '';
}
$openingBalanceDate = $repository->getOpeningBalanceDate($account);
$currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
// include this account in net-worth charts?
$includeNetWorth = $repository->getMetaValue($account, 'include_net_worth');

View File

@@ -86,7 +86,7 @@ class ReconcileController extends Controller
return redirect(route('accounts.index', [config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type))]));
}
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
// no start or end:
$range = app('navigation')->getViewRange(false);
@@ -197,7 +197,7 @@ class ReconcileController extends Controller
}
$reconciliation = $this->accountRepos->getReconciliation($account);
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$source = $reconciliation;
$destination = $account;
if (1 === bccomp($difference, '0')) {

View File

@@ -30,7 +30,6 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\PeriodOverview;
use Illuminate\Contracts\View\Factory;
@@ -101,7 +100,7 @@ class ShowController extends Controller
$page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$accountCurrency = $this->repository->getAccountCurrency($account);
$currency = $accountCurrency ?? Amount::getDefaultCurrency();
$currency = $accountCurrency ?? $this->defaultCurrency;
$fStart = $start->isoFormat($this->monthAndDayFormat);
$fEnd = $end->isoFormat($this->monthAndDayFormat);
$subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
@@ -178,7 +177,7 @@ class ShowController extends Controller
$subTitleIcon = config('firefly.subIconsByIdentifier.'.$account->accountType->type);
$page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$currency = $this->repository->getAccountCurrency($account) ?? Amount::getDefaultCurrency();
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
$periods = new Collection();

View File

@@ -77,7 +77,7 @@ class CreateController extends Controller
$periods[$current] = (string) trans('firefly.repeat_freq_'.$current);
}
$subTitle = (string) trans('firefly.create_new_bill');
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
// put previous url in session if not redirect from store (not "create another").
if (true !== session('bills.create.fromStore')) {

View File

@@ -85,11 +85,10 @@ class EditController extends Controller
$this->rememberPreviousUrl('bills.edit.url');
}
$currency = app('amount')->getDefaultCurrency();
$bill->amount_min = app('steam')->bcround($bill->amount_min, $currency->decimal_places);
$bill->amount_max = app('steam')->bcround($bill->amount_max, $currency->decimal_places);
$bill->amount_min = app('steam')->bcround($bill->amount_min, $bill->transactionCurrency->decimal_places);
$bill->amount_max = app('steam')->bcround($bill->amount_max, $bill->transactionCurrency->decimal_places);
$rules = $this->repository->getRulesForBill($bill);
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');

View File

@@ -86,11 +86,10 @@ class CreateController extends Controller
'half_year' => (string) trans('firefly.auto_budget_period_half_year'),
'yearly' => (string) trans('firefly.auto_budget_period_yearly'),
];
$currency = app('amount')->getDefaultCurrency();
$preFilled = [
'auto_budget_period' => $hasOldInput ? (bool) $request->old('auto_budget_period') : 'monthly',
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $currency->id,
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $this->defaultCurrency->id,
];
$request->session()->flash('preFilled', $preFilled);

View File

@@ -91,10 +91,9 @@ class EditController extends Controller
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$currency = app('amount')->getDefaultCurrency();
$preFilled = [
'active' => $hasOldInput ? (bool) $request->old('active') : $budget->active,
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $currency->id,
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $this->defaultCurrency->id,
];
if (null !== $autoBudget) {
$amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount;

View File

@@ -42,6 +42,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -106,7 +107,6 @@ class IndexController extends Controller
$end ??= session('end', today(config('app.timezone'))->endOfMonth());
}
$defaultCurrency = app('amount')->getDefaultCurrency();
$currencies = $this->currencyRepository->get();
$budgeted = '0';
$spent = '0';
@@ -119,14 +119,14 @@ class IndexController extends Controller
// get all available budgets:
$availableBudgets = $this->getAllAvailableBudgets($start, $end);
// get all active budgets:
$budgets = $this->getAllBudgets($start, $end, $currencies, $defaultCurrency);
$budgets = $this->getAllBudgets($start, $end, $currencies, $this->defaultCurrency);
$sums = $this->getSums($budgets);
// get budgeted for default currency:
if (0 === count($availableBudgets)) {
$budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency);
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
$budgeted = $this->blRepository->budgeted($start, $end, $this->defaultCurrency);
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $this->defaultCurrency);
$spent = $spentArr[$this->defaultCurrency->id]['sum'] ?? '0';
unset($spentArr);
}
@@ -136,6 +136,7 @@ class IndexController extends Controller
// get all inactive budgets, and simply list them:
$inactive = $this->repository->getInactiveBudgets();
$defaultCurrency = $this->defaultCurrency;
return view(
'budgets.index',
@@ -162,6 +163,7 @@ class IndexController extends Controller
private function getAllAvailableBudgets(Carbon $start, Carbon $end): array
{
Log::debug(sprintf('Start of getAllAvailableBudgets("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$converter = new ExchangeRateConverter();
// get all available budgets.
$ab = $this->abRepository->get($start, $end);

View File

@@ -103,7 +103,6 @@ class AccountController extends Controller
$currencies = [];
$chartData = [];
$tempData = [];
$default = Amount::getDefaultCurrency();
// grab all accounts and names
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]);
@@ -138,13 +137,13 @@ class AccountController extends Controller
continue;
}
Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $default->code : $key;
Log::debug(sprintf('Search code is %s', $searchCode));
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startBalance = ($startBalances[$account->id][$key] ?? '0');
Log::debug(sprintf('Start balance is %s', $startBalance));
// Log::debug(sprintf('Start balance is %s', $startBalance));
$diff = bcsub($endBalance, $startBalance);
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
if (0 !== bccomp($diff, '0')) {
@@ -562,7 +561,6 @@ class AccountController extends Controller
$currencies = [];
$chartData = [];
$tempData = [];
$default = Amount::getDefaultCurrency();
// grab all accounts and names
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::REVENUE->value]);
@@ -598,13 +596,13 @@ class AccountController extends Controller
continue;
}
Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $default->code : $key;
Log::debug(sprintf('Search code is %s', $searchCode));
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startBalance = ($startBalances[$account->id][$key] ?? '0');
Log::debug(sprintf('Start balance is %s', $startBalance));
// Log::debug(sprintf('Start balance is %s', $startBalance));
$diff = bcsub($endBalance, $startBalance);
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
if (0 !== bccomp($diff, '0')) {

View File

@@ -465,7 +465,7 @@ class BudgetController extends Controller
$chartGenerator->setStart($start);
$chartGenerator->setEnd($end);
$chartGenerator->convertToNative = $this->convertToNative;
$chartGenerator->default = Amount::getDefaultCurrency();
$chartGenerator->default = $this->defaultCurrency;
$chartData = $chartGenerator->generate();
$data = $this->generator->multiSet($chartData);

View File

@@ -118,7 +118,7 @@ abstract class Controller extends BaseController
$this->defaultCurrency =null;
// get shown-intro-preference:
if (auth()->check()) {
$this->defaultCurrency = app('amount')->getDefaultCurrency();
$this->defaultCurrency = Amount::getDefaultCurrency();
$language = Steam::getLanguage();
$locale = Steam::getLocale();
$darkMode = app('preferences')->get('darkMode', 'browser')->data;

View File

@@ -78,8 +78,7 @@ class BoxController extends Controller
$incomes = [];
$expenses = [];
$sums = [];
$currency = app('amount')->getDefaultCurrency();
$currency = $this->defaultCurrency;
// collect income of user:
/** @var GroupCollectorInterface $collector */
@@ -91,7 +90,7 @@ class BoxController extends Controller
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = $this->convertToNative ? $currency->id : (int) $journal['currency_id'];
$currencyId = $this->convertToNative && $this->defaultCurrency->id !== (int) $journal['currency_id'] ? $this->defaultCurrency->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd($incomes[$currencyId], app('steam')->positive($amount));
@@ -109,7 +108,7 @@ class BoxController extends Controller
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = $this->convertToNative ? $currency->id : (int) $journal['currency_id'];
$currencyId = $this->convertToNative ? $this->defaultCurrency->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$expenses[$currencyId] ??= '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
@@ -126,10 +125,10 @@ class BoxController extends Controller
$expenses[$currencyId] = app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false);
}
if (0 === count($sums)) {
$currency = app('amount')->getDefaultCurrency();
$sums[$currency->id] = app('amount')->formatAnything($currency, '0', false);
$incomes[$currency->id] = app('amount')->formatAnything($currency, '0', false);
$expenses[$currency->id] = app('amount')->formatAnything($currency, '0', false);
$currency = $this->defaultCurrency;
$sums[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false);
$incomes[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false);
$expenses[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false);
}
$response = [

View File

@@ -73,7 +73,7 @@ class ReconcileController extends Controller
{
$startBalance = $request->get('startBalance');
$endBalance = $request->get('endBalance');
$accountCurrency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$accountCurrency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$amount = '0';
$clearedAmount = '0';
@@ -193,7 +193,7 @@ class ReconcileController extends Controller
$startDate->subDay();
$end->endOfDay();
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$startBalance = Steam::finalAccountBalance($account, $startDate)['balance'];
$endBalance = Steam::finalAccountBalance($account, $end)['balance'];

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use FireflyIII\Events\Preferences\UserGroupChangedDefaultCurrency;
use FireflyIII\Events\Test\UserTestNotificationChannel;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\PreferencesRequest;
@@ -35,6 +36,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -258,6 +260,11 @@ class PreferencesController extends Controller
// convert native
$convertToNative = 1 === (int) $request->get('convertToNative');
if ($convertToNative && !$this->convertToNative) {
// set to true!
Log::debug('User sets convertToNative to true.');
event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
}
app('preferences')->set('convert_to_native', $convertToNative);
// custom fiscal year

View File

@@ -84,7 +84,7 @@ class CreateController extends Controller
{
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
$bills = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills());
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$tomorrow = today(config('app.timezone'));
$oldRepetitionType = $request->old('repetition_type');
$tomorrow->addDay();
@@ -129,7 +129,7 @@ class CreateController extends Controller
{
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
$bills = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills());
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$tomorrow = today(config('app.timezone'));
$oldRepetitionType = $request->old('repetition_type');
$tomorrow->addDay();

View File

@@ -62,8 +62,6 @@ class InstallController extends Controller
'migrate' => ['--seed' => true, '--force' => true],
'generate-keys' => [], // an exception :(
'firefly-iii:upgrade-database' => [],
// 'firefly-iii:correct-database' => [],
// 'firefly-iii:report-integrity' => [],
'firefly-iii:set-latest-version' => ['--james-is-cool' => true],
'firefly-iii:verify-security-alerts' => [],
];

View File

@@ -216,15 +216,14 @@ class ConvertController extends Controller
private function getLiabilities(): array
{
// make repositories
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$defaultCurrency = app('amount')->getDefaultCurrency();
$grouped = [];
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$grouped = [];
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
$role = 'l_'.$account->accountType->type;
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
@@ -239,15 +238,14 @@ class ConvertController extends Controller
private function getAssetAccounts(): array
{
// make repositories
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]);
$defaultCurrency = app('amount')->getDefaultCurrency();
$grouped = [];
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]);
$grouped = [];
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
if ('' === $role) {
$role = 'no_account_type';

View File

@@ -114,7 +114,7 @@ class CreateController extends Controller
$optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
$accountToTypes = config('firefly.account_to_transaction');
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
$parts = parse_url($previousUrl);
$search = sprintf('?%s', $parts['query'] ?? '');

View File

@@ -82,7 +82,7 @@ class EditController extends Controller
$title = $transactionGroup->transactionJournals()->count() > 1 ? $transactionGroup->title : $transactionGroup->transactionJournals()->first()->description;
$subTitle = (string) trans('firefly.edit_transaction_title', ['description' => $title]);
$subTitleIcon = 'fa-plus';
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$cash = $repository->getCashAccount();
$previousUrl = $this->rememberPreviousUrl('transactions.edit.url');
$parts = parse_url($previousUrl);

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Http\Middleware;
use Carbon\Carbon;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Controllers\RequestInformation;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
@@ -108,7 +109,7 @@ class Range
setlocale(LC_TIME, $localeArray);
$moneyResult = setlocale(LC_MONETARY, $localeArray);
// send error to view, if could not set money format
// send error to view, if it could not set money format
if (false === $moneyResult) {
app('log')->error('Could not set locale. The following array doesnt work: ', $localeArray);
app('view')->share('invalidMonetaryLocale', true);
@@ -117,7 +118,7 @@ class Range
// save some formats:
$monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale);
$dateTimeFormat = (string) trans('config.date_time_js', [], $locale);
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = Amount::getDefaultCurrency();
// also format for moment JS:
$madMomentJS = (string) trans('config.month_and_day_moment_js', [], $locale);

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Http\Requests;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -125,7 +126,7 @@ class PiggyBankStoreRequest extends FormRequest
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return app('amount')->getDefaultCurrency();
return Amount::getDefaultCurrency();
}
return $currency;

View File

@@ -27,6 +27,7 @@ use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -128,7 +129,7 @@ class PiggyBankUpdateRequest extends FormRequest
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return app('amount')->getDefaultCurrency();
return Amount::getDefaultCurrency();
}
return $currency;

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
@@ -101,4 +102,20 @@ class AvailableBudget extends Model
get: static fn ($value) => (int) $value,
);
}
protected function startDate(): Attribute
{
return Attribute::make(
get: fn (string $value) => Carbon::parse($value),
set: fn (Carbon $value) => $value->format('Y-m-d'),
);
}
protected function endDate(): Attribute
{
return Attribute::make(
get: fn (string $value) => Carbon::parse($value),
set: fn (Carbon $value) => $value->format('Y-m-d'),
);
}
}

View File

@@ -38,16 +38,16 @@ class RecurrenceRepetition extends Model
use ReturnsIntegerIdTrait;
use SoftDeletes;
#[\Deprecated]
#[\Deprecated] /** @deprecated */
public const int WEEKEND_DO_NOTHING = 1;
#[\Deprecated]
#[\Deprecated] /** @deprecated */
public const int WEEKEND_SKIP_CREATION = 2;
#[\Deprecated]
#[\Deprecated] /** @deprecated */
public const int WEEKEND_TO_FRIDAY = 3;
#[\Deprecated]
#[\Deprecated] /** @deprecated */
public const int WEEKEND_TO_MONDAY = 4;
protected $casts

View File

@@ -83,15 +83,17 @@ class ReturnsAvailableChannels
private static function returnUserChannels(User $user): array
{
Log::debug(sprintf('Checking channels for user #%d', $user->id));
$channels = ['mail'];
$slackUrl = app('preferences')->getEncryptedForUser($user, 'slack_webhook_url', '')->data;
$slackUrl = (string) app('preferences')->getEncryptedForUser($user, 'slack_webhook_url', '')->data;
if (UrlValidator::isValidWebhookURL($slackUrl)) {
$channels[] = 'slack';
}
// validate presence of of Ntfy settings.
if ('' !== (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data) {
Log::debug('Enabled ntfy.');
$ntfyTopic = (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data;
if ('' !== $ntfyTopic) {
Log::debug(sprintf('Enabled ntfy, "%s"', $ntfyTopic));
$channels[] = NtfyChannel::class;
}
if ('' === (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data) {

View File

@@ -550,9 +550,9 @@ class BillRepository implements BillRepositoryInterface
foreach ($set as $transactionJournal) {
$setAmount = bcadd($setAmount, Amount::getAmountFromJournalObject($transactionJournal));
}
Log::debug(sprintf('Bill #%d ("%s") with %d transaction(s) and sum %s %s', $bill->id, $bill->name, $set->count(), $currency->code, $setAmount));
// Log::debug(sprintf('Bill #%d ("%s") with %d transaction(s) and sum %s %s', $bill->id, $bill->name, $set->count(), $currency->code, $setAmount));
$return[$currency->id]['sum'] = bcadd($return[$currency->id]['sum'], $setAmount);
Log::debug(sprintf('Total sum is now %s', $return[$currency->id]['sum']));
// Log::debug(sprintf('Total sum is now %s', $return[$currency->id]['sum']));
}
return $return;
@@ -586,11 +586,11 @@ class BillRepository implements BillRepositoryInterface
$minField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_min' : 'amount_min';
$maxField = $convertToNative && $bill->transactionCurrency->id !== $default->id ? 'native_amount_max' : 'amount_max';
Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField));
// Log::debug(sprintf('min field is %s, max field is %s', $minField, $maxField));
if ($total > 0) {
$currency = $convertToNative && $bill->transactionCurrency->id !== $default->id ? $default : $bill->transactionCurrency;
$average = bcdiv(bcadd($bill->{$maxField}, $bill->{$minField}), '2');
$average = bcdiv(bcadd($bill->{$maxField} ?? '0', $bill->{$minField} ?? '0'), '2');
Log::debug(sprintf('Amount to pay is %s %s (%d times)', $currency->code, $average, $total));
$return[$currency->id] ??= [
'id' => (string) $currency->id,

View File

@@ -64,17 +64,19 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
*/
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
{
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
if (null !== $start && null !== $end) {
$query->where(
static function (Builder $q1) use ($start, $end): void { // @phpstan-ignore-line
$q1->where('start_date', '=', $start->format('Y-m-d H:i:s'));
$q1->where('end_date', '=', $end->format('Y-m-d H:i:s'));
$q1->where('start_date', '=', $start->format('Y-m-d'));
$q1->where('end_date', '=', $end->format('Y-m-d'));
}
);
}
$result = $query->get(['available_budgets.*']);
Log::debug(sprintf('Found %d available budgets between %s and %s', $result->count(), $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
return $query->get(['available_budgets.*']);
return $result;
}
/**
@@ -131,8 +133,8 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
Log::debug(sprintf('Now in %s(%s, %s)', __METHOD__, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$return = [];
$availableBudgets = $this->user->availableBudgets()
->where('start_date', $start->format('Y-m-d H:i:s'))
->where('end_date', $end->format('Y-m-d H:i:s'))->get()
->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->get()
;
Log::debug(sprintf('Found %d available budgets', $availableBudgets->count()));
@@ -214,9 +216,9 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
$availableBudget = new AvailableBudget();
$availableBudget->user()->associate($this->user);
$availableBudget->transactionCurrency()->associate($currency);
$availableBudget->start_date = $start->startOfDay()->format('Y-m-d'); // @phpstan-ignore-line
$availableBudget->start_date = $start->startOfDay();
$availableBudget->start_date_tz = $start->format('e');
$availableBudget->end_date = $end->endOfDay()->format('Y-m-d'); // @phpstan-ignore-line
$availableBudget->end_date = $end->endOfDay();
$availableBudget->end_date_tz = $end->format('e');
}
$availableBudget->amount = $amount;
@@ -249,9 +251,9 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
'user_group_id' => $this->user->user_group_id,
'transaction_currency_id' => $data['currency_id'],
'amount' => $data['amount'],
'start_date' => $start->format('Y-m-d'),
'start_date' => $start,
'start_date_tz' => $start->format('e'),
'end_date' => $end->format('Y-m-d'),
'end_date' => $end,
'end_date_tz' => $end->format('e'),
]
);
@@ -273,7 +275,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
$start = $data['start'];
if ($start instanceof Carbon) {
$start = $data['start']->startOfDay();
$availableBudget->start_date = $start->format('Y-m-d');
$availableBudget->start_date = $start;
$availableBudget->start_date_tz = $start->format('e');
$availableBudget->save();
}
@@ -283,7 +285,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
$end = $data['end'];
if ($end instanceof Carbon) {
$end = $data['end']->endOfDay();
$availableBudget->end_date = $end->format('Y-m-d');
$availableBudget->end_date = $end;
$availableBudget->end_date_tz = $end->format('e');
$availableBudget->save();
}

View File

@@ -287,7 +287,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
$amount = '' === $amount ? '0' : $amount;
$sum = bcadd($sum, $amount);
}
Log::debug(sprintf('Current amount in piggy bank #%d ("%s") is %s', $piggyBank->id, $piggyBank->name, $sum));
// Log::debug(sprintf('Current amount in piggy bank #%d ("%s") is %s', $piggyBank->id, $piggyBank->name, $sum));
return $sum;
}

View File

@@ -210,6 +210,10 @@ class Preferences
try {
$result->data = decrypt($result->data);
} catch (DecryptException $e) {
if ('The MAC is invalid.' === $e->getMessage()) {
Log::debug('Set data to NULL');
$result->data = null;
}
Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
return $result;
@@ -230,6 +234,10 @@ class Preferences
try {
$result->data = decrypt($result->data);
} catch (DecryptException $e) {
if ('The MAC is invalid.' === $e->getMessage()) {
Log::debug('Set data to NULL');
$result->data = null;
}
Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
return $result;

View File

@@ -97,7 +97,7 @@ class TransactionSummarizer
'currency_decimal_places' => $currencyDecimalPlaces,
];
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->{$method}($amount));
Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
// Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
}
Log::debug('End of sumExpenses.', $array);

View File

@@ -331,7 +331,7 @@ class Steam
if ($native->id === $accountCurrency?->id) {
$return['balance'] = bcadd('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance, $return['balance']);
}
Log::debug(sprintf('balance is (%s only) %s (with virtual balance)', $native->code, $this->bcround($return['balance'], 2)));
// Log::debug(sprintf('balance is (%s only) %s (with virtual balance)', $native->code, $this->bcround($return['balance'], 2)));
// native balance
$return['native_balance'] = (string) $account->transactions()
@@ -342,7 +342,7 @@ class Steam
;
// plus native virtual balance.
$return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['native_balance']);
Log::debug(sprintf('native_balance is (all transactions to %s) %s (with virtual balance)', $native->code, $this->bcround($return['native_balance'])));
// Log::debug(sprintf('native_balance is (all transactions to %s) %s (with virtual balance)', $native->code, $this->bcround($return['native_balance'])));
// plus foreign transactions in THIS currency.
$sum = (string) $account->transactions()
@@ -354,7 +354,7 @@ class Steam
;
$return['native_balance'] = bcadd($return['native_balance'], $sum);
Log::debug(sprintf('Foreign amount transactions add (%s only) %s, total native_balance is now %s', $native->code, $this->bcround($sum), $this->bcround($return['native_balance'])));
// Log::debug(sprintf('Foreign amount transactions add (%s only) %s, total native_balance is now %s', $native->code, $this->bcround($sum), $this->bcround($return['native_balance'])));
}
// balance(s) in other (all) currencies.
@@ -365,12 +365,12 @@ class Steam
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
;
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
Log::debug('All balances are (joined)', $others);
// Log::debug('All balances are (joined)', $others);
// if the account has no own currency preference, drop balance in favor of native balance
if ($hasCurrency && !$convertToNative) {
$return['balance'] = $others[$currency->code] ?? '0';
$return['native_balance'] = $others[$currency->code] ?? '0';
Log::debug(sprintf('Set balance + native_balance to %s', $return['balance']));
// Log::debug(sprintf('Set balance + native_balance to %s', $return['balance']));
}
// if the currency is the same as the native currency, set the native_balance to the balance for consistency.
@@ -379,16 +379,15 @@ class Steam
// }
if (!$hasCurrency && array_key_exists('balance', $return) && array_key_exists('native_balance', $return)) {
Log::debug('Account has no currency preference, dropping balance in favor of native balance.');
// Log::debug('Account has no currency preference, dropping balance in favor of native balance.');
$sum = bcadd($return['balance'], $return['native_balance']);
Log::debug(sprintf('%s + %s = %s', $return['balance'], $return['native_balance'], $sum));
// Log::debug(sprintf('%s + %s = %s', $return['balance'], $return['native_balance'], $sum));
$return['native_balance'] = $sum;
unset($return['balance']);
}
$final = array_merge($return, $others);
Log::debug('Return is', $final);
return $final;
return array_merge($return, $others);
// Log::debug('Return is', $final);
}
public function filterAccountBalances(array $total, Account $account, bool $convertToNative, ?TransactionCurrency $currency = null): array

40
composer.lock generated
View File

@@ -6364,16 +6364,16 @@
},
{
"name": "spatie/laravel-package-tools",
"version": "1.17.0",
"version": "1.18.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
"reference": "9ab30fd24f677e5aa370ea4cf6b41c517d16cf85"
"reference": "8332205b90d17164913244f4a8e13ab7e6761d29"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/9ab30fd24f677e5aa370ea4cf6b41c517d16cf85",
"reference": "9ab30fd24f677e5aa370ea4cf6b41c517d16cf85",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/8332205b90d17164913244f4a8e13ab7e6761d29",
"reference": "8332205b90d17164913244f4a8e13ab7e6761d29",
"shasum": ""
},
"require": {
@@ -6412,7 +6412,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
"source": "https://github.com/spatie/laravel-package-tools/tree/1.17.0"
"source": "https://github.com/spatie/laravel-package-tools/tree/1.18.0"
},
"funding": [
{
@@ -6420,7 +6420,7 @@
"type": "github"
}
],
"time": "2024-12-09T16:29:14+00:00"
"time": "2024-12-30T13:13:39+00:00"
},
{
"name": "spatie/period",
@@ -10287,20 +10287,20 @@
},
{
"name": "barryvdh/reflection-docblock",
"version": "v2.2.0",
"version": "v2.3.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git",
"reference": "db125e8df4329bd45f2da405aab007f502f38531"
"reference": "818be8de6af4d16ef3ad51ea9234b3d37026ee5f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/db125e8df4329bd45f2da405aab007f502f38531",
"reference": "db125e8df4329bd45f2da405aab007f502f38531",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/818be8de6af4d16ef3ad51ea9234b3d37026ee5f",
"reference": "818be8de6af4d16ef3ad51ea9234b3d37026ee5f",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "^8.5.14|^9"
@@ -10312,7 +10312,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2.x-dev"
"dev-master": "2.3.x-dev"
}
},
"autoload": {
@@ -10333,9 +10333,9 @@
}
],
"support": {
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.2.0"
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.3.0"
},
"time": "2024-12-28T10:00:03+00:00"
"time": "2024-12-30T10:35:04+00:00"
},
{
"name": "cloudcreativity/json-api-testing",
@@ -11147,16 +11147,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.3.1",
"version": "v5.4.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
"shasum": ""
},
"require": {
@@ -11199,9 +11199,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
},
"time": "2024-10-08T18:51:32+00:00"
"time": "2024-12-30T11:07:19+00:00"
},
{
"name": "phar-io/manifest",

View File

@@ -28,47 +28,48 @@ return [
'download_enabled' => env('ENABLE_EXTERNAL_RATES', false),
// if currencies are added, default rates must be added as well!
// last exchange rate update: 6-6-2022
// last exchange rate update: 2024-12-30
// source: https://www.xe.com/currencyconverter/
'date' => '2022-06-06',
'date' => '2024-12-30',
// all rates are from EUR to $currency:
'rates' => [
// europa
'EUR' => 1,
'HUF' => 387.9629,
'GBP' => 0.85420754,
'UAH' => 31.659752,
'PLN' => 4.581788,
'TRY' => 17.801397,
'DKK' => 7.4389753,
'HUF' => 410.79798,
'GBP' => 0.82858703,
'UAH' => 43.485934,
'PLN' => 4.2708542,
'TRY' => 36.804124,
'DKK' => 7.4591,
'RON' => 4.9768699,
// Americas
'USD' => 1.0722281,
'BRL' => 5.0973173,
'CAD' => 1.3459969,
'MXN' => 20.899824,
'USD' => 1.0430046,
'BRL' => 6.4639113,
'CAD' => 1.5006908,
'MXN' => 21.249542,
// Oceania currencies
'IDR' => 15466.299,
'AUD' => 1.4838549,
'NZD' => 1.6425829,
'IDR' => 16860.057,
'AUD' => 1.6705648,
'NZD' => 1.8436945,
// africa
'EGP' => 19.99735,
'MAD' => 10.573307,
'ZAR' => 16.413167,
'EGP' => 53.038174,
'MAD' => 10.521629,
'ZAR' => 19.460263,
// asia
'JPY' => 140.15257,
'RMB' => 7.1194265,
'CNY' => 1,
'RUB' => 66.000895,
'INR' => 83.220481,
'JPY' => 164.74767,
'RMB' => 7.6138994,
'CNY' => 7.6138994,
'RUB' => 108.56771,
'INR' => 89.157391,
// int
'ILS' => 3.5712508,
'CHF' => 1.0323891,
'HRK' => 7.5220845,
'ILS' => 3.8428028,
'CHF' => 0.94044969,
'HRK' => 7.5345, // replaced by EUR
],
];

View File

@@ -81,7 +81,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2024-12-30',
'version' => 'develop/2024-12-31',
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25,

6
package-lock.json generated
View File

@@ -12114,9 +12114,9 @@
"license": "ISC"
},
"node_modules/yaml": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
"integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
"integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
"dev": true,
"license": "ISC",
"bin": {

View File

@@ -21,7 +21,7 @@
"apply_rules_checkbox": "Regeln anwenden",
"fire_webhooks_checkbox": "Webhooks abfeuern",
"no_budget_pointer": "Sie scheinen noch keine Budgets festgelegt zu haben. Sie sollten einige davon auf der Seite <a href=\"budgets\">Budgets<\/a> anlegen. Budgets k\u00f6nnen Ihnen dabei helfen, den \u00dcberblick \u00fcber die Ausgaben zu behalten.",
"no_bill_pointer": "Sie scheinen noch kein Abonnement zu haben. Sie sollten einige auf der Seite <a href=\"subscriptions\">Abonnement<\/a> erstellen. Abonnements k\u00f6nnen Ihnen helfen, den \u00dcberblick \u00fcber Ihre Ausgaben zu behalten.",
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.",
"source_account": "Quellkonto",
"hidden_fields_preferences": "Sie k\u00f6nnen weitere Buchungsoptionen in Ihren <a href=\"preferences\">Einstellungen<\/a> aktivieren.",
"destination_account": "Zielkonto",
@@ -36,7 +36,7 @@
"is_reconciled_fields_dropped": "Da diese Buchung abgeglichen ist, k\u00f6nnen Sie weder die Konten noch den\/die Betrag\/Betr\u00e4ge aktualisieren.",
"tags": "Schlagw\u00f6rter",
"no_budget": "(kein Budget)",
"no_bill": "(kein Abonnement)",
"no_bill": "(no subscription)",
"category": "Kategorie",
"attachments": "Anh\u00e4nge",
"notes": "Notizen",
@@ -52,7 +52,7 @@
"destination_account_reconciliation": "Sie k\u00f6nnen das Zielkonto einer Kontenausgleichsbuchung nicht bearbeiten.",
"source_account_reconciliation": "Sie k\u00f6nnen das Quellkonto einer Kontenausgleichsbuchung nicht bearbeiten.",
"budget": "Budget",
"bill": "Abonnement",
"bill": "Subscription",
"you_create_withdrawal": "Sie haben eine Ausgabe erstellt.",
"you_create_transfer": "Sie erstellen eine Umbuchung.",
"you_create_deposit": "Sie haben eine Einnahme erstellt.",
@@ -130,15 +130,15 @@
"response": "Antwort",
"visit_webhook_url": "Webhook-URL besuchen",
"reset_webhook_secret": "Webhook Secret zur\u00fccksetzen",
"header_exchange_rates": "Wechselkurse",
"exchange_rates_intro": "Firefly III unterst\u00fctzt das Herunterladen und Verwenden von Wechselkursen. Lesen Sie mehr dar\u00fcber in <a href=\u201ehttps:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\u201c>der Dokumentation<\/a>.",
"exchange_rates_from_to": "Zwischen {from} und {to} (und umgekehrt)",
"exchange_rates_intro_rates": "Firefly III verwendet die folgenden Wechselkurse. Der Kehrwert wird automatisch berechnet, wenn er nicht angegeben wurde. Wenn f\u00fcr das Datum der Transaktion kein Wechselkurs vorhanden ist, sucht Firefly III in der Vergangenheit nach einem Kurs. Wenn keine vorhanden sind, wird der Kurs \u201e1\u201c verwendet.",
"header_exchange_rates_rates": "Wechselkurse",
"header_exchange_rates_table": "Tabelle mit Wechselkursen",
"help_rate_form": "An diesem Tag, wie viele {to} werden Sie f\u00fcr {from} bekommen?",
"add_new_rate": "Neuen Wechselkurs hinzuf\u00fcgen",
"save_new_rate": "Neuen Kurs speichern"
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",
"header_exchange_rates_table": "Table with exchange rates",
"help_rate_form": "On this day, how many {to} will you get for one {from}?",
"add_new_rate": "Add a new exchange rate",
"save_new_rate": "Save new rate"
},
"form": {
"url": "URL",
@@ -158,7 +158,7 @@
"webhook_delivery": "Zustellung",
"from_currency_to_currency": "{from} &rarr; {to}",
"to_currency_from_currency": "{to} &rarr; {from}",
"rate": "Kurs"
"rate": "Rate"
},
"list": {
"active": "Aktiv?",

View File

@@ -21,7 +21,7 @@
"apply_rules_checkbox": "Regels toepassen",
"fire_webhooks_checkbox": "Webhooks starten",
"no_budget_pointer": "Je hebt nog geen budgetten. Maak er een aantal op de <a href=\"budgets\">budgetten<\/a>-pagina. Met budgetten kan je je uitgaven beter bijhouden.",
"no_bill_pointer": "Je hebt nog geen abonnementen. Maak er een aantal op de <a href=\"subscriptions\">abonnementenpagina<\/a>. Met abonnementen kan je uitgaven bijhouden.",
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.",
"source_account": "Bronrekening",
"hidden_fields_preferences": "Je kan meer transactieopties inschakelen in je <a href=\"preferences\">instellingen<\/a>.",
"destination_account": "Doelrekening",
@@ -36,7 +36,7 @@
"is_reconciled_fields_dropped": "Omdat deze transactie al is afgestemd, kan je het bedrag noch de rekeningen wijzigen.",
"tags": "Tags",
"no_budget": "(geen budget)",
"no_bill": "(geen abonnement)",
"no_bill": "(no subscription)",
"category": "Categorie",
"attachments": "Bijlagen",
"notes": "Notities",
@@ -52,7 +52,7 @@
"destination_account_reconciliation": "Je kan de doelrekening van een afstemming niet wijzigen.",
"source_account_reconciliation": "Je kan de bronrekening van een afstemming niet wijzigen.",
"budget": "Budget",
"bill": "Abonnement",
"bill": "Subscription",
"you_create_withdrawal": "Je maakt een uitgave.",
"you_create_transfer": "Je maakt een overschrijving.",
"you_create_deposit": "Je maakt inkomsten.",
@@ -130,15 +130,15 @@
"response": "Reactie",
"visit_webhook_url": "Bezoek URL van webhook",
"reset_webhook_secret": "Reset webhook-geheim",
"header_exchange_rates": "Wisselkoersen",
"exchange_rates_intro": "Firefly III kan wisselkoersen downloaden en gebruiken. Lees hier meer over in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">de documentatie<\/a>.",
"exchange_rates_from_to": "Tussen {from} en {to} (en andersom)",
"exchange_rates_intro_rates": "Firefly III gebruikt de volgende wisselkoersen. De inverse berekent zichzelf als deze niet is opgegeven. Als er geen wisselkoers bestaat voor de datum van de transactie, gaat Firefly III terug in de tijd om er een te vinden. Als er geen aanwezig is, zal de koers \"1\" gebruikt worden.",
"header_exchange_rates_rates": "Wisselkoersen",
"header_exchange_rates_table": "Tabel met wisselkoersen",
"help_rate_form": "Hoeveel {to} krijg je op deze dag voor \u00e9\u00e9n {from}?",
"add_new_rate": "Nieuwe wisselkoers toevoegen",
"save_new_rate": "Nieuwe wisselkoers opslaan"
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",
"header_exchange_rates_table": "Table with exchange rates",
"help_rate_form": "On this day, how many {to} will you get for one {from}?",
"add_new_rate": "Add a new exchange rate",
"save_new_rate": "Save new rate"
},
"form": {
"url": "URL",
@@ -158,7 +158,7 @@
"webhook_delivery": "Bericht",
"from_currency_to_currency": "{from} &rarr; {to}",
"to_currency_from_currency": "{to} &rarr; {from}",
"rate": "Wisselkoers"
"rate": "Rate"
},
"list": {
"active": "Actief?",

View File

@@ -46,13 +46,16 @@ final class BillControllerTest extends TestCase
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$userGroup = UserGroup::create(['title' => 'Test Group']);
return User::create([
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
'user_group_id' => $userGroup->id,
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestBills(int $count, User $user): void

View File

@@ -46,13 +46,16 @@ final class BudgetControllerTest extends TestCase
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$userGroup = UserGroup::create(['title' => 'Test Group']);
return User::create([
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
'user_group_id' => $userGroup->id,
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestBudgets(int $count, User $user): void

View File

@@ -28,6 +28,7 @@ use FireflyIII\Models\Category;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
/**
* Class CategoryControllerTest
@@ -45,10 +46,16 @@ final class CategoryControllerTest extends TestCase
protected function createAuthenticatedUser(): User
{
return User::create([
'email' => 'test@email.com',
'password' => 'password',
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestCategories(int $count, User $user): void

View File

@@ -0,0 +1,183 @@
<?php
/*
* CurrencyControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* 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 Tests\integration\Api\Autocomplete;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
/**
* Class CurrencyControllerTest
*
* @internal
*
* @coversNothing
*/
final class CurrencyControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\CurrencyController
*/
use RefreshDatabase;
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestCurrencies(int $count, bool $enabled): void
{
for ($i = 1; $i <= $count; ++$i) {
$currency = TransactionCurrency::create([
'name' => 'Currency '.$i,
'code' => 'CUR'.$i,
'symbol' => 'C'.$i,
'decimal_places' => $i,
'enabled' => $enabled,
]);
}
}
public function testGivenAnUnauthenticatedRequestWhenCallingTheCurrenciesEndpointThenReturns401HttpCode(): void
{
// test API
$response = $this->get(route('api.v1.autocomplete.currencies'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated","exception":"AuthenticationException"}');
}
public function testGivenAuthenticatedRequestWhenCallingTheCurrenciesEndpointThenReturns200HttpCode(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
// test API
$response = $this->get(route('api.v1.autocomplete.currencies'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWhenCallingTheCurrenciesEndpointThenReturnsACollectionOfEnabledCurrencies(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
// create test data
$this->createTestCurrencies(10, true);
// test API
$response = $this->get(route('api.v1.autocomplete.currencies'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonFragment(['name' => 'Currency 1']);
$response->assertJsonFragment(['code' => 'CUR1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'code',
'symbol',
'decimal_places',
],
]);
$response->assertJsonCount(10);
}
public function testGivenAuthenticatedRequestWhenCallingTheCurrenciesEndpointDoesNotReturnDisabledCurrencies(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
// create test data
$this->createTestCurrencies(10, false);
// test API
$response = $this->get(route('api.v1.autocomplete.currencies'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(0);
}
public function testGivenAuthenticatedRequestWhenCallingTheCurrenciesEndpointWithQueryThenReturnsCurrenciesWithLimit(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
// create test data
$this->createTestCurrencies(5, true);
// test API
$response = $this->get(route('api.v1.autocomplete.currencies', ['query' => 'Currency 1']), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonFragment(['name' => 'Currency 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'code',
'symbol',
'decimal_places',
],
]);
$response->assertJsonCount(1);
}
public function testGivenAuthenticatedRequestWhenCallingTheCurrenciesEndpointWithQueryThenReturnsCurrenciesThatMatchQuery(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestCurrencies(20, true);
$response = $this->get(route('api.v1.autocomplete.currencies', [
'query' => 'Currency 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Currency 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
}
}

View File

@@ -0,0 +1,156 @@
<?php
/*
* ObjectGroupControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* 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 Tests\integration\Api\Autocomplete;
use FireflyIII\Models\ObjectGroup;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
use FireflyIII\User;
use FireflyIII\Models\UserGroup;
/**
* Class ObjectGroupControllerTest
*
* @internal
*
* @coversNothing
*/
final class ObjectGroupControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\ObjectGroupController
*/
use RefreshDatabase;
protected function createAuthenticatedUser(): User
{
$userGroup = UserGroup::create(['title' => 'Test Group']);
$user = User::create([
'email' => 'test@email.com',
'password' => 'password',
]);
$user->user_group_id = $userGroup->id;
$user->save();
return $user;
}
private function createTestObjectGroups(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {
$objectGroup = ObjectGroup::create([
'title' => 'Object Group '.$i,
'order' => $i,
'user_group_id' => $user->user_group_id,
'user_id' => $user->id,
]);
}
}
public function testGivenAnUnauthenticatedRequestWhenCallingTheObjectGroupEndpointThenReturn401HttpCode(): void
{
$response = $this->get(route('api.v1.autocomplete.object-groups'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated","exception":"AuthenticationException"}');
}
public function testGivenAuthenticatedRequestWhenCallingTheObjectGroupsEndpointThenReturns200HttpCode(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
// test API
$response = $this->get(route('api.v1.autocomplete.object-groups'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWhenCallingTheObjectGroupsEndpointThenReturnsObjectGroups(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestObjectGroups(5, $user);
$response = $this->get(route('api.v1.autocomplete.object-groups'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(5);
$response->assertJsonFragment(['title' => 'Object Group 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'title',
],
]);
}
public function testGivenAuthenticatedRequestWhenCallingTheObjectGroupsEndpointWithQueryThenReturnsObjectGroupsWithLimit(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestObjectGroups(5, $user);
$response = $this->get(route('api.v1.autocomplete.object-groups', [
'query' => 'Object Group',
'limit' => 3,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(3);
$response->assertJsonFragment(['name' => 'Object Group 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'title',
],
]);
}
public function testGivenAuthenticatedRequestWhenCallingTheObjectGroupsEndpointWithQueryThenReturnsObjectGroupsThatMatchQuery(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestObjectGroups(20, $user);
$response = $this->get(route('api.v1.autocomplete.object-groups', [
'query' => 'Object Group 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Object Group 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
$response->assertJsonMissing(['name' => 'Object Group 2']);
}
}