mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-16 00:01:18 +00:00
Compare commits
25 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f727a38b69 | ||
|
|
c11a5384da | ||
|
|
ed92cbd4b8 | ||
|
|
a9ea32772f | ||
|
|
6fde693e7a | ||
|
|
2e46d9ba33 | ||
|
|
e36f8deb08 | ||
|
|
1631b422f1 | ||
|
|
b58d809063 | ||
|
|
9e34314dbc | ||
|
|
e4aa218b5f | ||
|
|
31722477d4 | ||
|
|
ec82105433 | ||
|
|
146e164f04 | ||
|
|
7d37c93988 | ||
|
|
73dffacd9a | ||
|
|
d37304fa68 | ||
|
|
62f4da6063 | ||
|
|
760da08ab7 | ||
|
|
e68c4d4408 | ||
|
|
46a200aa1f | ||
|
|
c422039335 | ||
|
|
5971d155ef | ||
|
|
9e373a9b0d | ||
|
|
4fb61646b4 |
24
.ci/php-cs-fixer/composer.lock
generated
24
.ci/php-cs-fixer/composer.lock
generated
@@ -1641,16 +1641,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49"
|
||||
"reference": "87a71856f2f56e4100373e92529eed3171695cfb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49",
|
||||
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb",
|
||||
"reference": "87a71856f2f56e4100373e92529eed3171695cfb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1685,7 +1685,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/finder/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1701,7 +1701,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-23T06:56:12+00:00"
|
||||
"time": "2024-12-30T19:00:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -2390,16 +2390,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/stopwatch",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/stopwatch.git",
|
||||
"reference": "696f418b0d722a4225e1c3d95489d262971ca924"
|
||||
"reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/696f418b0d722a4225e1c3d95489d262971ca924",
|
||||
"reference": "696f418b0d722a4225e1c3d95489d262971ca924",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df",
|
||||
"reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2432,7 +2432,7 @@
|
||||
"description": "Provides a way to profile code",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/stopwatch/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/stopwatch/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2448,7 +2448,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
"time": "2024-12-18T14:28:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
|
||||
60
.github/workflows/release.yml
vendored
60
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -143,6 +143,7 @@ class BudgetLimitHandler
|
||||
);
|
||||
$availableBudget->save();
|
||||
Log::debug(sprintf('ID of new AB is #%d', $availableBudget->id));
|
||||
$this->calculateAmount($availableBudget);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
@@ -115,7 +114,7 @@ class AccountController extends Controller
|
||||
|
||||
// loop the accounts, then check for balance and currency info.
|
||||
foreach ($accounts as $account) {
|
||||
Log::debug(sprintf('Now in account #%d ("%s")', $account->id, $account->name));
|
||||
// Log::debug(sprintf('[a] Now in account #%d ("%s")', $account->id, $account->name));
|
||||
$expenses = $endBalances[$account->id] ?? false;
|
||||
if (false === $expenses) {
|
||||
Log::error(sprintf('Found no end balance for account #%d', $account->id));
|
||||
@@ -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]);
|
||||
@@ -575,7 +573,7 @@ class AccountController extends Controller
|
||||
|
||||
// loop the accounts, then check for balance and currency info.
|
||||
foreach ($accounts as $account) {
|
||||
Log::debug(sprintf('Now in account #%d ("%s")', $account->id, $account->name));
|
||||
// Log::debug(sprintf('[b] Now in account #%d ("%s")', $account->id, $account->name));
|
||||
$expenses = $endBalances[$account->id] ?? false;
|
||||
if (false === $expenses) {
|
||||
Log::error(sprintf('Found no end balance for account #%d', $account->id));
|
||||
@@ -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')) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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'];
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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' => [],
|
||||
];
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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'] ?? '');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ class CreditRecalculateService
|
||||
|
||||
private function processWorkAccount(Account $account): void
|
||||
{
|
||||
Log::debug(sprintf('Now processing account #%d ("%s"). All amounts with 2 decimals!', $account->id, $account->name));
|
||||
Log::debug(sprintf('Now processing account #%d ("%s").', $account->id, $account->name));
|
||||
// get opening balance (if present)
|
||||
$this->repository->setUser($account->user);
|
||||
$direction = (string) $this->repository->getMetaValue($account, 'liability_direction');
|
||||
@@ -230,7 +230,7 @@ class CreditRecalculateService
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug('Opening balance is valid');
|
||||
// Log::debug('Opening balance is valid');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +263,7 @@ class CreditRecalculateService
|
||||
return $leftOfDebt;
|
||||
}
|
||||
if (TransactionTypeEnum::LIABILITY_CREDIT->value === $type || TransactionTypeEnum::OPENING_BALANCE->value === $type) {
|
||||
Log::warning(sprintf('Transaction type is "%s", so do nothing.', $type));
|
||||
// Log::warning(sprintf('Transaction type is "%s", so do nothing.', $type));
|
||||
|
||||
return $leftOfDebt;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -310,7 +310,15 @@ class Steam
|
||||
*/
|
||||
public function finalAccountBalance(Account $account, Carbon $date): array
|
||||
{
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty($date);
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Now in finalAccountBalance(#%d, "%s", "%s")', $account->id, $account->name, $date->format('Y-m-d H:i:s')));
|
||||
|
||||
$native = Amount::getDefaultCurrencyByUserGroup($account->user->userGroup);
|
||||
$convertToNative = Amount::convertToNative($account->user);
|
||||
$accountCurrency = $this->getAccountCurrency($account);
|
||||
@@ -331,7 +339,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 +350,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 +362,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 +373,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 +387,18 @@ 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);
|
||||
// Log::debug('Return is', $final);
|
||||
$cache->store($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
|
||||
|
||||
@@ -26,13 +26,14 @@ namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class UpdatePiggybank
|
||||
@@ -53,7 +54,7 @@ class UpdatePiggybank implements ActionInterface
|
||||
{
|
||||
$actionValue = $this->action->getValue($journal);
|
||||
|
||||
app('log')->debug(sprintf('Triggered rule action UpdatePiggybank on journal #%d', $journal['transaction_journal_id']));
|
||||
Log::debug(sprintf('Triggered rule action UpdatePiggybank on journal #%d', $journal['transaction_journal_id']));
|
||||
|
||||
// refresh the transaction type.
|
||||
/** @var User $user */
|
||||
@@ -64,7 +65,7 @@ class UpdatePiggybank implements ActionInterface
|
||||
|
||||
$piggyBank = $this->findPiggyBank($user, $actionValue);
|
||||
if (null === $piggyBank) {
|
||||
app('log')->info(
|
||||
Log::info(
|
||||
sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $actionValue, $this->action->id, $this->action->rule_id)
|
||||
);
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_piggy', ['name' => $actionValue])));
|
||||
@@ -72,20 +73,19 @@ class UpdatePiggybank implements ActionInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
app('log')->debug(sprintf('Found piggy bank #%d ("%s")', $piggyBank->id, $piggyBank->name));
|
||||
|
||||
/** @var Transaction $source */
|
||||
$source = $journalObj->transactions()->where('amount', '<', 0)->first();
|
||||
Log::debug(sprintf('Found piggy bank #%d ("%s")', $piggyBank->id, $piggyBank->name));
|
||||
|
||||
/** @var Transaction $destination */
|
||||
$destination = $journalObj->transactions()->where('amount', '>', 0)->first();
|
||||
|
||||
if ($source->account_id === $piggyBank->account_id) {
|
||||
app('log')->debug('Piggy bank account is linked to source, so remove amount from piggy bank.');
|
||||
|
||||
throw new FireflyException('Reference the correct account here.');
|
||||
$this->removeAmount($piggyBank, $journal, $journalObj, $destination->amount);
|
||||
$accounts = $this->getAccounts($journalObj);
|
||||
Log::debug(sprintf('Source account is #%d: "%s"', $accounts['source']->id, $accounts['source']->name));
|
||||
Log::debug(sprintf('Destination account is #%d: "%s"', $accounts['destination']->id, $accounts['source']->name));
|
||||
|
||||
// if connected to source but not to destination, needs to be removed from source account connected to piggy bank.
|
||||
if ($this->isConnected($piggyBank, $accounts['source']) && !$this->isConnected($piggyBank, $accounts['destination'])) {
|
||||
Log::debug('Piggy bank account is linked to source, so remove amount from piggy bank.');
|
||||
$this->removeAmount($piggyBank, $journal, $journalObj, $accounts['source'], $destination->amount);
|
||||
event(
|
||||
new TriggeredAuditLog(
|
||||
$this->action->rule,
|
||||
@@ -103,9 +103,11 @@ class UpdatePiggybank implements ActionInterface
|
||||
|
||||
return true;
|
||||
}
|
||||
if ($destination->account_id === $piggyBank->account_id) {
|
||||
app('log')->debug('Piggy bank account is linked to source, so add amount to piggy bank.');
|
||||
$this->addAmount($piggyBank, $journal, $journalObj, $destination->amount);
|
||||
|
||||
// if connected to destination but not to source, needs to be removed from source account connected to piggy bank.
|
||||
if (!$this->isConnected($piggyBank, $accounts['source']) && $this->isConnected($piggyBank, $accounts['destination'])) {
|
||||
Log::debug('Piggy bank account is linked to source, so add amount to piggy bank.');
|
||||
$this->addAmount($piggyBank, $journal, $journalObj, $accounts['destination'], $destination->amount);
|
||||
|
||||
event(
|
||||
new TriggeredAuditLog(
|
||||
@@ -125,13 +127,13 @@ class UpdatePiggybank implements ActionInterface
|
||||
|
||||
return true;
|
||||
}
|
||||
app('log')->info(
|
||||
sprintf(
|
||||
'Piggy bank is not linked to source ("#%d") or destination ("#%d"), so no action will be taken.',
|
||||
$source->account_id,
|
||||
$destination->account_id
|
||||
)
|
||||
);
|
||||
if ($this->isConnected($piggyBank, $accounts['source']) && $this->isConnected($piggyBank, $accounts['destination'])) {
|
||||
Log::info(sprintf('Piggy bank is linked to BOTH source ("#%d") and destination ("#%d"), so no action will be taken.', $accounts['source']->id, $accounts['destination']->id));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_link_piggy', ['name' => $actionValue])));
|
||||
|
||||
return false;
|
||||
}
|
||||
Log::info(sprintf('Piggy bank is not linked to source ("#%d") or destination ("#%d"), so no action will be taken.', $accounts['source']->id, $accounts['destination']->id));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_link_piggy', ['name' => $actionValue])));
|
||||
|
||||
return false;
|
||||
@@ -139,80 +141,102 @@ class UpdatePiggybank implements ActionInterface
|
||||
|
||||
private function findPiggyBank(User $user, string $name): ?PiggyBank
|
||||
{
|
||||
return $user->piggyBanks()->where('piggy_banks.name', $name)->first();
|
||||
/** @var PiggyBankRepositoryInterface $repository */
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUser($user);
|
||||
|
||||
return $repository->findByName($name);
|
||||
}
|
||||
|
||||
private function removeAmount(PiggyBank $piggyBank, array $array, TransactionJournal $journal, string $amount): void
|
||||
private function removeAmount(PiggyBank $piggyBank, array $array, TransactionJournal $journal, Account $account, string $amount): void
|
||||
{
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUser($journal->user);
|
||||
|
||||
// how much can we remove from this piggy bank?
|
||||
$toRemove = $repository->getCurrentAmount($piggyBank);
|
||||
app('log')->debug(sprintf('Amount is %s, max to remove is %s', $amount, $toRemove));
|
||||
$toRemove = $repository->getCurrentAmount($piggyBank, $account);
|
||||
Log::debug(sprintf('Amount is %s, max to remove is %s', $amount, $toRemove));
|
||||
|
||||
// if $amount is bigger than $toRemove, shrink it.
|
||||
$amount = -1 === bccomp($amount, $toRemove) ? $amount : $toRemove;
|
||||
app('log')->debug(sprintf('Amount is now %s', $amount));
|
||||
Log::debug(sprintf('Amount is now %s', $amount));
|
||||
|
||||
// if amount is zero, stop.
|
||||
if (0 === bccomp('0', $amount)) {
|
||||
app('log')->warning('Amount left is zero, stop.');
|
||||
Log::warning('Amount left is zero, stop.');
|
||||
event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_remove_zero_piggy', ['name' => $piggyBank->name])));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure we can remove amount:
|
||||
throw new FireflyException('Reference the correct account here.');
|
||||
if (false === $repository->canRemoveAmount($piggyBank, $amount)) {
|
||||
app('log')->warning(sprintf('Cannot remove %s from piggy bank.', $amount));
|
||||
if (false === $repository->canRemoveAmount($piggyBank, $account, $amount)) {
|
||||
Log::warning(sprintf('Cannot remove %s from piggy bank.', $amount));
|
||||
event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_remove_from_piggy', ['amount' => $amount, 'name' => $piggyBank->name])));
|
||||
|
||||
return;
|
||||
}
|
||||
app('log')->debug(sprintf('Will now remove %s from piggy bank.', $amount));
|
||||
Log::debug(sprintf('Will now remove %s from piggy bank.', $amount));
|
||||
|
||||
throw new FireflyException('Reference the correct account here.');
|
||||
$repository->removeAmount($piggyBank, $amount, $journal);
|
||||
$repository->removeAmount($piggyBank, $account, $amount, $journal);
|
||||
}
|
||||
|
||||
private function addAmount(PiggyBank $piggyBank, array $array, TransactionJournal $journal, string $amount): void
|
||||
private function addAmount(PiggyBank $piggyBank, array $array, TransactionJournal $journal, Account $account, string $amount): void
|
||||
{
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUser($journal->user);
|
||||
|
||||
// how much can we add to the piggy bank?
|
||||
if (0 !== bccomp($piggyBank->target_amount, '0')) {
|
||||
$toAdd = bcsub($piggyBank->target_amount, $repository->getCurrentAmount($piggyBank));
|
||||
app('log')->debug(sprintf('Max amount to add to piggy bank is %s, amount is %s', $toAdd, $amount));
|
||||
$toAdd = bcsub($piggyBank->target_amount, $repository->getCurrentAmount($piggyBank, $account));
|
||||
Log::debug(sprintf('Max amount to add to piggy bank is %s, amount is %s', $toAdd, $amount));
|
||||
|
||||
// update amount to fit:
|
||||
$amount = -1 === bccomp($amount, $toAdd) ? $amount : $toAdd;
|
||||
app('log')->debug(sprintf('Amount is now %s', $amount));
|
||||
Log::debug(sprintf('Amount is now %s', $amount));
|
||||
}
|
||||
if (0 === bccomp($piggyBank->target_amount, '0')) {
|
||||
app('log')->debug('Target amount is zero, can add anything.');
|
||||
Log::debug('Target amount is zero, can add anything.');
|
||||
}
|
||||
|
||||
// if amount is zero, stop.
|
||||
if (0 === bccomp('0', $amount)) {
|
||||
app('log')->warning('Amount left is zero, stop.');
|
||||
Log::warning('Amount left is zero, stop.');
|
||||
event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_add_zero_piggy', ['name' => $piggyBank->name])));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure we can add amount:
|
||||
throw new FireflyException('Reference the correct account here.');
|
||||
if (false === $repository->canAddAmount($piggyBank, $amount)) {
|
||||
app('log')->warning(sprintf('Cannot add %s to piggy bank.', $amount));
|
||||
if (false === $repository->canAddAmount($piggyBank, $account, $amount)) {
|
||||
Log::warning(sprintf('Cannot add %s to piggy bank.', $amount));
|
||||
event(new RuleActionFailedOnArray($this->action, $array, trans('rules.cannot_add_to_piggy', ['amount' => $amount, 'name' => $piggyBank->name])));
|
||||
|
||||
return;
|
||||
}
|
||||
app('log')->debug(sprintf('Will now add %s to piggy bank.', $amount));
|
||||
Log::debug(sprintf('Will now add %s to piggy bank.', $amount));
|
||||
|
||||
$repository->addAmount($piggyBank, $amount, $journal);
|
||||
$repository->addAmount($piggyBank, $account, $amount, $journal);
|
||||
}
|
||||
|
||||
private function getAccounts(TransactionJournal $journal): array
|
||||
{
|
||||
return [
|
||||
'source' => $journal->transactions()->where('amount', '<', '0')->first()?->account,
|
||||
'destination' => $journal->transactions()->where('amount', '>', '0')->first()?->account,
|
||||
];
|
||||
}
|
||||
|
||||
private function isConnected(PiggyBank $piggyBank, ?Account $link): bool
|
||||
{
|
||||
if (null === $link) {
|
||||
return false;
|
||||
}
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
if ($account->id === $link->id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Log::debug(sprintf('Piggy bank is not connected to account #%d "%s"', $account->id, $account->name));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
110
composer.lock
generated
110
composer.lock
generated
@@ -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",
|
||||
@@ -7246,16 +7246,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49"
|
||||
"reference": "87a71856f2f56e4100373e92529eed3171695cfb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49",
|
||||
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb",
|
||||
"reference": "87a71856f2f56e4100373e92529eed3171695cfb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7290,7 +7290,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/finder/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7306,20 +7306,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-23T06:56:12+00:00"
|
||||
"time": "2024-12-30T19:00:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.2.1",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "ff4df2b68d1c67abb9fef146e6540ea16b58d99e"
|
||||
"reference": "339ba21476eb184290361542f732ad12c97591ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/ff4df2b68d1c67abb9fef146e6540ea16b58d99e",
|
||||
"reference": "ff4df2b68d1c67abb9fef146e6540ea16b58d99e",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec",
|
||||
"reference": "339ba21476eb184290361542f732ad12c97591ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7385,7 +7385,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.2.1"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7401,7 +7401,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-07T08:50:44+00:00"
|
||||
"time": "2024-12-30T18:35:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@@ -7483,16 +7483,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "e88a66c3997859532bc2ddd6dd8f35aba2711744"
|
||||
"reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/e88a66c3997859532bc2ddd6dd8f35aba2711744",
|
||||
"reference": "e88a66c3997859532bc2ddd6dd8f35aba2711744",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/62d1a43796ca3fea3f83a8470dfe63a4af3bc588",
|
||||
"reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7541,7 +7541,7 @@
|
||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7557,20 +7557,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-13T18:58:46+00:00"
|
||||
"time": "2024-12-30T19:00:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v7.2.1",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "d8ae58eecae44c8e66833e76cc50a4ad3c002d97"
|
||||
"reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/d8ae58eecae44c8e66833e76cc50a4ad3c002d97",
|
||||
"reference": "d8ae58eecae44c8e66833e76cc50a4ad3c002d97",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3c432966bd8c7ec7429663105f5a02d7e75b4306",
|
||||
"reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7655,7 +7655,7 @@
|
||||
"description": "Provides a structured process for converting a Request into a Response",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v7.2.1"
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7671,7 +7671,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-11T12:09:10+00:00"
|
||||
"time": "2024-12-31T14:59:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
@@ -9082,16 +9082,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v7.2.0",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "dc89e16b44048ceecc879054e5b7f38326ab6cc5"
|
||||
"reference": "e2674a30132b7cc4d74540d6c2573aa363f05923"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/dc89e16b44048ceecc879054e5b7f38326ab6cc5",
|
||||
"reference": "dc89e16b44048ceecc879054e5b7f38326ab6cc5",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/e2674a30132b7cc4d74540d6c2573aa363f05923",
|
||||
"reference": "e2674a30132b7cc4d74540d6c2573aa363f05923",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9157,7 +9157,7 @@
|
||||
"description": "Provides tools to internationalize your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation/tree/v7.2.0"
|
||||
"source": "https://github.com/symfony/translation/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9173,7 +9173,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-12T20:47:56+00:00"
|
||||
"time": "2024-12-07T08:18:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation-contracts",
|
||||
@@ -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",
|
||||
@@ -11616,16 +11616,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.12.13",
|
||||
"version": "1.12.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "9b469068840cfa031e1deaf2fa1886d00e20680f"
|
||||
"reference": "e73868f809e68fff33be961ad4946e2e43ec9e38"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b469068840cfa031e1deaf2fa1886d00e20680f",
|
||||
"reference": "9b469068840cfa031e1deaf2fa1886d00e20680f",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e73868f809e68fff33be961ad4946e2e43ec9e38",
|
||||
"reference": "e73868f809e68fff33be961ad4946e2e43ec9e38",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11670,7 +11670,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-17T17:00:20+00:00"
|
||||
"time": "2024-12-31T07:26:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-deprecation-rules",
|
||||
|
||||
@@ -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
|
||||
],
|
||||
];
|
||||
|
||||
@@ -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/2025-01-01',
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 25,
|
||||
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -3007,9 +3007,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express-serve-static-core": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz",
|
||||
"integrity": "sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.3.tgz",
|
||||
"integrity": "sha512-JEhMNwUJt7bw728CydvYzntD0XJeTmDnvwLlbfbAhE7Tbslm/ax6bdIiUwTgeVlZTsJQPwZwKpAkyDtIjsvx3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3133,9 +3133,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz",
|
||||
"integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==",
|
||||
"version": "22.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.3.tgz",
|
||||
"integrity": "sha512-DifAyw4BkrufCILvD3ucnuN8eydUfc/C1GlyrnI+LK6543w5/L3VeVgf05o3B4fqSXP1dKYLOZsKfutpxPzZrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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} → {to}",
|
||||
"to_currency_from_currency": "{to} → {from}",
|
||||
"rate": "Wisselkoers"
|
||||
"rate": "Rate"
|
||||
},
|
||||
"list": {
|
||||
"active": "Actief?",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"apply_rules_checkbox": "Uporabite pravila",
|
||||
"fire_webhooks_checkbox": "Spro\u017eite Webhooke",
|
||||
"no_budget_pointer": "Zdi se, da \u0161e nimate prora\u010duna. Ustvarite jih nekaj na strani <a href=\"budgets\">prora\u010duni<\/a>. Prora\u010duni vam lahko pomagajo spremljati stro\u0161ke.",
|
||||
"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.",
|
||||
"no_bill_pointer": "Zdi se, da \u0161e nimate naro\u010dnine. Ustvarite jih na strani za <a href=\"subscriptions\">naro\u010dnine<\/a>. Naro\u010dnine vam lahko pomagajo spremljati stro\u0161ke.",
|
||||
"source_account": "Izvorni ra\u010dun",
|
||||
"hidden_fields_preferences": "Ve\u010d mo\u017enosti transakcije lahko omogo\u010dite v <a href=\"preferences\">nastavitvah<\/a>.",
|
||||
"destination_account": "Ciljni ra\u010dun",
|
||||
@@ -36,7 +36,7 @@
|
||||
"is_reconciled_fields_dropped": "Ker je ta transakcija usklajena, ne boste mogli posodobiti ra\u010dunov niti zneskov.",
|
||||
"tags": "Oznake",
|
||||
"no_budget": "(brez prora\u010duna)",
|
||||
"no_bill": "(no subscription)",
|
||||
"no_bill": "(brez naro\u010dnin)",
|
||||
"category": "Kategorija",
|
||||
"attachments": "Priloge",
|
||||
"notes": "Opombe",
|
||||
@@ -52,7 +52,7 @@
|
||||
"destination_account_reconciliation": "Pri usklajevalni transakciji ni mo\u017eno urejati ciljnega ra\u010duna.",
|
||||
"source_account_reconciliation": "Pri usklajevalni transakciji ni mo\u017eno urejati izvornega ra\u010duna.",
|
||||
"budget": "Prora\u010dun",
|
||||
"bill": "Subscription",
|
||||
"bill": "Naro\u010dnina",
|
||||
"you_create_withdrawal": "Ustvarjate odliv.",
|
||||
"you_create_transfer": "Ustvarjate prenos.",
|
||||
"you_create_deposit": "Ustvarja\u0161 priliv.",
|
||||
@@ -130,15 +130,15 @@
|
||||
"response": "Odziv",
|
||||
"visit_webhook_url": "Obi\u0161\u010dite URL webhooka",
|
||||
"reset_webhook_secret": "Ponastavi skrivno kodo webhooka",
|
||||
"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"
|
||||
"header_exchange_rates": "Menjalni te\u010daji",
|
||||
"exchange_rates_intro": "Firefly III podpira prenos in uporabo menjalnih te\u010dajev. Preberite ve\u010d o tem v <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">dokumentaciji<\/a>.",
|
||||
"exchange_rates_from_to": "Med {from} in {to} (in obratno)",
|
||||
"exchange_rates_intro_rates": "Firefly III uporablja naslednje menjalne te\u010daje. Obratna vrednost se samodejno izra\u010duna, \u010de ni na voljo. \u010ce na dan transakcije ni menjalnega te\u010daja, se bo Firefly III vrnil v preteklost, da bi ga na\u0161el. \u010ce jih ni, se uporabi te\u010daj \"1\".",
|
||||
"header_exchange_rates_rates": "Menjalni te\u010daji",
|
||||
"header_exchange_rates_table": "Tabela s te\u010daji",
|
||||
"help_rate_form": "Na ta dan, koliko {to} boste dobili za enega {from}?",
|
||||
"add_new_rate": "Dodaj nov menjalni te\u010daj",
|
||||
"save_new_rate": "Shrani nov te\u010daj"
|
||||
},
|
||||
"form": {
|
||||
"url": "URL",
|
||||
@@ -158,7 +158,7 @@
|
||||
"webhook_delivery": "Dostava",
|
||||
"from_currency_to_currency": "{from} → {to}",
|
||||
"to_currency_from_currency": "{to} → {from}",
|
||||
"rate": "Rate"
|
||||
"rate": "Te\u010daj"
|
||||
},
|
||||
"list": {
|
||||
"active": "Aktiviran?",
|
||||
|
||||
@@ -217,9 +217,9 @@ return [
|
||||
'button_register' => 'Register',
|
||||
'authorization' => 'Authorization',
|
||||
'active_bills_only' => 'active subscription only',
|
||||
'active_bills_only_total' => 'all active subscription',
|
||||
'active_exp_bills_only' => 'active and expected subscription only',
|
||||
'active_exp_bills_only_total' => 'all active expected subscription only',
|
||||
'active_bills_only_total' => 'all active subscriptions',
|
||||
'active_exp_bills_only' => 'active and expected subscriptions only',
|
||||
'active_exp_bills_only_total' => 'all active expected subscriptions only',
|
||||
'per_period_sum_1D' => 'Expected daily costs',
|
||||
'per_period_sum_1W' => 'Expected weekly costs',
|
||||
'per_period_sum_1M' => 'Expected monthly costs',
|
||||
@@ -1328,7 +1328,7 @@ return [
|
||||
'rule_for_bill_title' => 'Auto-generated rule for subscription ":name"',
|
||||
'rule_for_bill_description' => 'This rule is auto-generated to try to match subscription ":name".',
|
||||
'create_rule_for_bill' => 'Create a new rule for subscription ":name"',
|
||||
'create_rule_for_bill_txt' => 'You have just created a new subscription called ":name", congratulations!Firefly III can automagically match new withdrawals to this subscription. For example, whenever you pay your rent, the subscription "rent" will be linked to the expense. This way, Firefly III can accurately show you which subscriptions are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct subscription. Please check out the triggers to see if they are correct, and add some if they\'re wrong.',
|
||||
'create_rule_for_bill_txt' => 'You have just created a new subscription called ":name", congratulations! Firefly III can automagically match new withdrawals to this subscription. For example, whenever you pay your rent, the subscription "rent" will be linked to the expense. This way, Firefly III can accurately show you which subscriptions are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct subscription. Please check out the triggers to see if they are correct, and add some if they\'re wrong.',
|
||||
'new_rule_for_bill_title' => 'Rule for subscription ":name"',
|
||||
'new_rule_for_bill_description' => 'This rule marks transactions for subscription ":name".',
|
||||
|
||||
|
||||
@@ -23,56 +23,57 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'main_message' => 'Action ":action", present in rule ":rule", could not be applied to transaction #:group: :error',
|
||||
'find_or_create_tag_failed' => 'Could not find or create tag ":tag"',
|
||||
'tag_already_added' => 'Tag ":tag" is already linked to this transaction',
|
||||
'inspect_transaction' => 'Inspect transaction ":title" @ Firefly III',
|
||||
'inspect_rule' => 'Inspect rule ":title" @ Firefly III',
|
||||
'journal_other_user' => 'This transaction doesn\'t belong to the user',
|
||||
'no_such_journal' => 'This transaction doesn\'t exist',
|
||||
'journal_already_no_budget' => 'This transaction has no budget, so it cannot be removed',
|
||||
'journal_already_no_category' => 'This transaction had no category, so it cannot be removed',
|
||||
'journal_already_no_notes' => 'This transaction had no notes, so they cannot be removed',
|
||||
'journal_not_found' => 'Firefly III can\'t find the requested transaction',
|
||||
'split_group' => 'Firefly III cannot execute this action on a transaction with multiple splits',
|
||||
'is_already_withdrawal' => 'This transaction is already a withdrawal',
|
||||
'is_already_deposit' => 'This transaction is already a deposit',
|
||||
'is_already_transfer' => 'This transaction is already a transfer',
|
||||
'is_not_transfer' => 'This transaction is not a transfer',
|
||||
'complex_error' => 'Something complicated went wrong. Sorry about that. Please inspect the logs of Firefly III',
|
||||
'no_valid_opposing' => 'Conversion failed because there is no valid account named ":account"',
|
||||
'new_notes_empty' => 'The notes to be set are empty',
|
||||
'unsupported_transaction_type_withdrawal' => 'Firefly III cannot convert a ":type" to a withdrawal',
|
||||
'unsupported_transaction_type_deposit' => 'Firefly III cannot convert a ":type" to a deposit',
|
||||
'unsupported_transaction_type_transfer' => 'Firefly III cannot convert a ":type" to a transfer',
|
||||
'already_has_source_asset' => 'This transaction already has ":name" as the source asset account',
|
||||
'already_has_destination_asset' => 'This transaction already has ":name" as the destination asset account',
|
||||
'already_has_destination' => 'This transaction already has ":name" as the destination account',
|
||||
'already_has_source' => 'This transaction already has ":name" as the source account',
|
||||
'already_linked_to_subscription' => 'The transaction is already linked to subscription ":name"',
|
||||
'already_linked_to_category' => 'The transaction is already linked to category ":name"',
|
||||
'already_linked_to_budget' => 'The transaction is already linked to budget ":name"',
|
||||
'cannot_find_subscription' => 'Firefly III can\'t find subscription ":name"',
|
||||
'no_notes_to_move' => 'The transaction has no notes to move to the description field',
|
||||
'no_tags_to_remove' => 'The transaction has no tags to remove',
|
||||
'not_withdrawal' => 'The transaction is not a withdrawal',
|
||||
'not_deposit' => 'The transaction is not a deposit',
|
||||
'cannot_find_tag' => 'Firefly III can\'t find tag ":tag"',
|
||||
'cannot_find_asset' => 'Firefly III can\'t find asset account ":name"',
|
||||
'cannot_find_accounts' => 'Firefly III can\'t find the source or destination account',
|
||||
'cannot_find_source_transaction' => 'Firefly III can\'t find the source transaction',
|
||||
'cannot_find_destination_transaction' => 'Firefly III can\'t find the destination transaction',
|
||||
'cannot_find_source_transaction_account' => 'Firefly III can\'t find the source transaction account',
|
||||
'cannot_find_destination_transaction_account' => 'Firefly III can\'t find the destination transaction account',
|
||||
'cannot_find_piggy' => 'Firefly III can\'t find a piggy bank named ":name"',
|
||||
'no_link_piggy' => 'This transaction\'s accounts are not linked to the piggy bank, so no action will be taken',
|
||||
'cannot_unlink_tag' => 'Tag ":tag" isn\'t linked to this transaction',
|
||||
'cannot_find_budget' => 'Firefly III can\'t find budget ":name"',
|
||||
'cannot_find_category' => 'Firefly III can\'t find category ":name"',
|
||||
'cannot_set_budget' => 'Firefly III can\'t set budget ":name" to a transaction of type ":type"',
|
||||
'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.',
|
||||
'cannot_remove_zero_piggy' => 'Cannot remove zero amount from piggy bank ":name"',
|
||||
'cannot_remove_from_piggy' => 'Cannot remove ":amount" from piggy bank ":name"',
|
||||
'cannot_add_zero_piggy' => 'Cannot add zero amount to piggy bank ":name"',
|
||||
'cannot_add_to_piggy' => 'Cannot add ":amount" to piggy bank ":name"',
|
||||
'main_message' => 'Action ":action", present in rule ":rule", could not be applied to transaction #:group: :error',
|
||||
'find_or_create_tag_failed' => 'Could not find or create tag ":tag"',
|
||||
'tag_already_added' => 'Tag ":tag" is already linked to this transaction',
|
||||
'inspect_transaction' => 'Inspect transaction ":title" @ Firefly III',
|
||||
'inspect_rule' => 'Inspect rule ":title" @ Firefly III',
|
||||
'journal_other_user' => 'This transaction doesn\'t belong to the user',
|
||||
'no_such_journal' => 'This transaction doesn\'t exist',
|
||||
'journal_already_no_budget' => 'This transaction has no budget, so it cannot be removed',
|
||||
'journal_already_no_category' => 'This transaction had no category, so it cannot be removed',
|
||||
'journal_already_no_notes' => 'This transaction had no notes, so they cannot be removed',
|
||||
'journal_not_found' => 'Firefly III can\'t find the requested transaction',
|
||||
'split_group' => 'Firefly III cannot execute this action on a transaction with multiple splits',
|
||||
'is_already_withdrawal' => 'This transaction is already a withdrawal',
|
||||
'is_already_deposit' => 'This transaction is already a deposit',
|
||||
'is_already_transfer' => 'This transaction is already a transfer',
|
||||
'is_not_transfer' => 'This transaction is not a transfer',
|
||||
'complex_error' => 'Something complicated went wrong. Sorry about that. Please inspect the logs of Firefly III',
|
||||
'no_valid_opposing' => 'Conversion failed because there is no valid account named ":account"',
|
||||
'new_notes_empty' => 'The notes to be set are empty',
|
||||
'unsupported_transaction_type_withdrawal' => 'Firefly III cannot convert a ":type" to a withdrawal',
|
||||
'unsupported_transaction_type_deposit' => 'Firefly III cannot convert a ":type" to a deposit',
|
||||
'unsupported_transaction_type_transfer' => 'Firefly III cannot convert a ":type" to a transfer',
|
||||
'already_has_source_asset' => 'This transaction already has ":name" as the source asset account',
|
||||
'already_has_destination_asset' => 'This transaction already has ":name" as the destination asset account',
|
||||
'already_has_destination' => 'This transaction already has ":name" as the destination account',
|
||||
'already_has_source' => 'This transaction already has ":name" as the source account',
|
||||
'already_linked_to_subscription' => 'The transaction is already linked to subscription ":name"',
|
||||
'already_linked_to_category' => 'The transaction is already linked to category ":name"',
|
||||
'already_linked_to_budget' => 'The transaction is already linked to budget ":name"',
|
||||
'cannot_find_subscription' => 'Firefly III can\'t find subscription ":name"',
|
||||
'no_notes_to_move' => 'The transaction has no notes to move to the description field',
|
||||
'no_tags_to_remove' => 'The transaction has no tags to remove',
|
||||
'not_withdrawal' => 'The transaction is not a withdrawal',
|
||||
'not_deposit' => 'The transaction is not a deposit',
|
||||
'cannot_find_tag' => 'Firefly III can\'t find tag ":tag"',
|
||||
'cannot_find_asset' => 'Firefly III can\'t find asset account ":name"',
|
||||
'cannot_find_accounts' => 'Firefly III can\'t find the source or destination account',
|
||||
'cannot_find_source_transaction' => 'Firefly III can\'t find the source transaction',
|
||||
'cannot_find_destination_transaction' => 'Firefly III can\'t find the destination transaction',
|
||||
'cannot_find_source_transaction_account' => 'Firefly III can\'t find the source transaction account',
|
||||
'cannot_find_destination_transaction_account' => 'Firefly III can\'t find the destination transaction account',
|
||||
'cannot_find_piggy' => 'Firefly III can\'t find a piggy bank named ":name"',
|
||||
'no_link_piggy' => 'This transaction\'s accounts are not linked to the piggy bank, so no action will be taken',
|
||||
'both_link_piggy' => 'This transaction\'s accounts are both linked to the piggy bank, so no action will be taken',
|
||||
'cannot_unlink_tag' => 'Tag ":tag" isn\'t linked to this transaction',
|
||||
'cannot_find_budget' => 'Firefly III can\'t find budget ":name"',
|
||||
'cannot_find_category' => 'Firefly III can\'t find category ":name"',
|
||||
'cannot_set_budget' => 'Firefly III can\'t set budget ":name" to a transaction of type ":type"',
|
||||
'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.',
|
||||
'cannot_remove_zero_piggy' => 'Cannot remove zero amount from piggy bank ":name"',
|
||||
'cannot_remove_from_piggy' => 'Cannot remove ":amount" from piggy bank ":name"',
|
||||
'cannot_add_zero_piggy' => 'Cannot add zero amount to piggy bank ":name"',
|
||||
'cannot_add_to_piggy' => 'Cannot add ":amount" to piggy bank ":name"',
|
||||
];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
183
tests/integration/Api/Autocomplete/CurrencyControllerTest.php
Normal file
183
tests/integration/Api/Autocomplete/CurrencyControllerTest.php
Normal 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);
|
||||
}
|
||||
}
|
||||
156
tests/integration/Api/Autocomplete/ObjectGroupControllerTest.php
Normal file
156
tests/integration/Api/Autocomplete/ObjectGroupControllerTest.php
Normal 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']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user