Compare commits

...

58 Commits

Author SHA1 Message Date
James Cole
2c3f032a2b Merge branch 'release/v6.1.6' 2024-01-06 11:13:41 +01:00
James Cole
de57ab0874 Update meta files for new release. 2024-01-06 11:11:18 +01:00
James Cole
6fb4aaecd3 Fix a very dumb bug. 2024-01-06 11:09:40 +01:00
James Cole
45fdbf5a11 Merge tag 'v6.1.5' into develop
v6.1.5
2024-01-06 10:59:05 +01:00
James Cole
c6615a7b17 Merge branch 'release/v6.1.5' 2024-01-06 10:59:02 +01:00
James Cole
0efb3d2dcf Fix currency validation. 2024-01-06 08:33:38 +01:00
James Cole
b8a58f83ee New packages. 2024-01-06 07:59:46 +01:00
James Cole
110228e65e Fix phpstan issue. 2024-01-06 07:49:50 +01:00
James Cole
8ad27e0eda Update meta files for new release. 2024-01-06 07:42:00 +01:00
James Cole
2e0d90c685 Expand edit transaction form. 2024-01-06 07:26:03 +01:00
James Cole
bd2ecb13b8 Change time for rule. 2024-01-05 18:09:19 +01:00
James Cole
5725570dbb Add marker. Seems fastest solution. 2024-01-05 14:47:44 +01:00
James Cole
11f77685e4 Experimental code cleanup. 2024-01-05 14:29:59 +01:00
James Cole
0521c46d27 test 2024-01-05 14:15:26 +01:00
James Cole
50d6225590 test 2024-01-05 14:15:02 +01:00
James Cole
df55f7de79 test 2024-01-05 14:13:44 +01:00
James Cole
5152ae9622 test 2024-01-05 14:11:06 +01:00
James Cole
075d0da63d test 2024-01-05 14:10:07 +01:00
James Cole
d804df2a2f test 2024-01-05 14:09:47 +01:00
James Cole
ff0f8beb81 Of course phpstan has an opinion on this lol 2024-01-05 14:07:13 +01:00
James Cole
c00be92f97 Finalize create transaction form. 2024-01-05 14:04:44 +01:00
James Cole
88f6221424 Small code fix. 2024-01-05 11:09:52 +01:00
James Cole
f9463e02a2 Fix null pointer 2024-01-05 10:55:46 +01:00
James Cole
25a23801be Fix error mail 2024-01-05 10:55:07 +01:00
James Cole
fe7bb02dc5 Clean up min/max sizes of requests. 2024-01-05 09:48:59 +01:00
James Cole
68edcfc4e8 Clean up files and add alias 2024-01-05 08:12:17 +01:00
James Cole
5f8a24a684 Add newline. 2024-01-04 15:43:51 +01:00
James Cole
0a5d62605a Code cleanup and new translations. 2024-01-04 15:42:00 +01:00
James Cole
1873be8d95 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2024-01-04 15:41:18 +01:00
James Cole
01892c3828 Merge pull request #8348 from lemuelroberto/develop
Update outdated documentation URLs in .env.example
2024-01-04 15:41:00 +01:00
Lemuel Roberto Bonifácio
b87e60c72f Update outdated documentation URLs in .env.example 2024-01-04 11:32:36 -03:00
James Cole
3a083f88b5 Clean up code. 2024-01-04 14:59:55 +01:00
James Cole
566bb2f097 Expand create transaction form. 2024-01-04 14:59:37 +01:00
James Cole
1ba7847d84 Add more details in message. 2024-01-04 11:46:23 +01:00
James Cole
c32044a8eb Smaller notes 2024-01-04 11:41:03 +01:00
James Cole
72a2d417af Change log levels. 2024-01-04 08:35:58 +01:00
James Cole
09c18d6d44 More audit logs. 2024-01-04 08:34:57 +01:00
James Cole
84ae6a633e Add some audit logs. 2024-01-04 08:32:42 +01:00
James Cole
82749cea07 Sanity check in date. 2024-01-04 07:51:37 +01:00
James Cole
23aa0e3ba3 Add some audit log info. 2024-01-04 07:48:51 +01:00
James Cole
8be27a2201 Small code cleanup 2024-01-04 07:44:52 +01:00
James Cole
ff98f3cc3e Expand create transaction form. 2024-01-04 07:26:45 +01:00
James Cole
01c4d25646 Better currency validation for foreign amount 2024-01-04 07:26:12 +01:00
James Cole
292b9ac9d0 Fix wording for https://github.com/firefly-iii/firefly-iii/issues/8328 2024-01-04 07:25:24 +01:00
James Cole
6bdae03961 Extra fix for https://github.com/firefly-iii/firefly-iii/issues/8328 2024-01-04 06:22:47 +01:00
James Cole
7426c6aac3 Split form in parts, add "edit" page. 2024-01-03 19:34:50 +01:00
James Cole
211526c032 Expand new transaction form. 2024-01-03 17:43:05 +01:00
James Cole
e6fe08dd61 Update translations. 2024-01-03 13:05:54 +01:00
James Cole
7bba67130a Merge pull request #8335 from maureenferreira/patch-2
Update intro.php
2024-01-03 07:28:43 +00:00
maureenferreira
7186d8ddfd Update intro.php
Signed-off-by: maureenferreira <142938968+maureenferreira@users.noreply.github.com>
2024-01-03 00:19:18 -06:00
James Cole
1a6bc6decd Merge branch 'release/v6.1.4' 2024-01-02 22:29:55 +01:00
James Cole
5b11c86113 Merge tag 'v6.1.4' into develop
v6.1.4
2024-01-02 22:29:55 +01:00
James Cole
98b95ab891 Fix issue #8328 2024-01-02 22:28:58 +01:00
James Cole
c3068d10bf Merge tag 'v6.1.3' into develop
v6.1.3
2024-01-02 21:23:34 +01:00
James Cole
fa1a1b084b Merge branch 'release/v6.1.3' 2024-01-02 21:23:33 +01:00
James Cole
387e44b8b9 Update changelog. 2024-01-02 21:23:14 +01:00
James Cole
6dafa89a15 Fix https://github.com/firefly-iii/firefly-iii/issues/8326 2024-01-02 21:22:42 +01:00
James Cole
5b5b8008b0 Merge tag 'v6.1.2' into develop
v6.1.2
2024-01-02 20:26:54 +01:00
356 changed files with 4027 additions and 1907 deletions

View File

@@ -226,21 +226,22 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.45.0",
"version": "v3.46.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "c0daa33cb2533cd73f48dde1c70c2afa3e7953b5"
"reference": "be6831c9af1740470d2a773119b9273f8ac1c3d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/c0daa33cb2533cd73f48dde1c70c2afa3e7953b5",
"reference": "c0daa33cb2533cd73f48dde1c70c2afa3e7953b5",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/be6831c9af1740470d2a773119b9273f8ac1c3d2",
"reference": "be6831c9af1740470d2a773119b9273f8ac1c3d2",
"shasum": ""
},
"require": {
"composer/semver": "^3.4",
"composer/xdebug-handler": "^3.0.3",
"ext-filter": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"php": "^7.4 || ^8.0",
@@ -304,7 +305,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.45.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.46.0"
},
"funding": [
{
@@ -312,7 +313,7 @@
"type": "github"
}
],
"time": "2023-12-30T02:07:07+00:00"
"time": "2024-01-03T21:38:46+00:00"
},
{
"name": "psr/container",

View File

@@ -78,7 +78,7 @@ PAPERTRAIL_HOST=
PAPERTRAIL_PORT=
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite
# For other database types, please see the FAQ: https://docs.firefly-iii.org/references/faq/install/#i-want-to-use-sqlite
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
# Use "pgsql" for PostgreSQL
# Use "mysql" for MySQL and MariaDB.
@@ -150,7 +150,7 @@ COOKIE_SECURE=false
COOKIE_SAMESITE=lax
# If you want Firefly III to email you, update these settings
# For instructions, see: https://docs.firefly-iii.org/firefly-iii/advanced-installation/email/#email
# For instructions, see: https://docs.firefly-iii.org/how-to/firefly-iii/advanced/notifications/#email
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
MAIL_MAILER=log
MAIL_HOST=null
@@ -214,7 +214,7 @@ VALID_URL_PROTOCOLS=
# - 'web' (default, uses built in DB)
# - 'remote_user_guard' for Authelia etc
# Read more about these settings in the documentation.
# https://docs.firefly-iii.org/firefly-iii/advanced-installation/authentication
# https://docs.firefly-iii.org/how-to/firefly-iii/advanced/authentication/
#
# LDAP is no longer supported :(
#
@@ -269,7 +269,7 @@ ALLOW_WEBHOOKS=false
# 1. Set this token to any 32-character value (this is important!).
# 2. Use this token in the cron URL instead of a user's command line token that you can find in /profile
#
# For more info: https://docs.firefly-iii.org/firefly-iii/advanced-installation/cron/
# For more info: https://docs.firefly-iii.org/how-to/firefly-iii/advanced/cron/
#
# You can set this variable from a file by appending it with _FILE
#

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
/node_modules
/storage/*.key
/vendor
public/hot
npm-debug.log
yarn-error.log
.env

View File

@@ -45,6 +45,7 @@ use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class DestroyController
@@ -175,12 +176,14 @@ class DestroyController extends Controller
$count = $account->transactions()->count();
if (true === $this->unused && 0 === $count) {
app('log')->info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name));
Log::channel('audit')->info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name));
$service->destroy($account, null);
continue;
}
if (false === $this->unused) {
app('log')->info(sprintf('Deleting account #%d "%s"', $account->id, $account->name));
Log::channel('audit')->info(sprintf('Deleted account #%d "%s"', $account->id, $account->name));
$service->destroy($account, null);
}
}

View File

@@ -59,9 +59,7 @@ class MoveTransactionsRequest extends FormRequest
/**
* Configure the validator instance with special rules for after the basic validation rules.
*
* @param validator $validator
* TODO this is duplicate
* TODO this is duplicate.
*/
public function withValidator(Validator $validator): void
{
@@ -81,12 +79,12 @@ class MoveTransactionsRequest extends FormRequest
$data = $validator->getData();
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$original = $repository->find((int)$data['original_account']);
$destination = $repository->find((int)$data['destination_account']);
$original = $repository->find((int) $data['original_account']);
$destination = $repository->find((int) $data['destination_account']);
// not the same type:
if ($original->accountType->type !== $destination->accountType->type) {
$validator->errors()->add('title', (string)trans('validation.same_account_type'));
$validator->errors()->add('title', (string) trans('validation.same_account_type'));
return;
}
@@ -96,7 +94,7 @@ class MoveTransactionsRequest extends FormRequest
// check different scenario's.
if (null === $originalCurrency xor null === $destinationCurrency) {
$validator->errors()->add('title', (string)trans('validation.same_account_currency'));
$validator->errors()->add('title', (string) trans('validation.same_account_currency'));
return;
}
@@ -105,7 +103,7 @@ class MoveTransactionsRequest extends FormRequest
return;
}
if ($originalCurrency->code !== $destinationCurrency->code) {
$validator->errors()->add('title', (string)trans('validation.same_account_currency'));
$validator->errors()->add('title', (string) trans('validation.same_account_currency'));
}
}
}

View File

@@ -101,7 +101,7 @@ class StoreRequest extends FormRequest
'type' => 'required|max:1024|min:1|'.sprintf('in:%s', $types),
'iban' => ['iban', 'nullable', new UniqueIban(null, $type)],
'bic' => 'bic|nullable',
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber(null, $type)],
'account_number' => ['min:1', 'max:255', 'nullable', new UniqueAccountNumber(null, $type)],
'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
'virtual_balance' => 'numeric|nullable',
@@ -117,7 +117,7 @@ class StoreRequest extends FormRequest
'liability_amount' => ['required_with:liability_start_date', new IsValidPositiveAmount()],
'liability_start_date' => 'required_with:liability_amount|date',
'liability_direction' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:credit,debit',
'interest' => 'between:0,100|numeric',
'interest' => 'min:0|max:100|numeric',
'interest_period' => sprintf('nullable|in:%s', implode(',', config('firefly.interest_periods'))),
'notes' => 'min:0|max:65536',
];

View File

@@ -91,7 +91,7 @@ class UpdateRequest extends FormRequest
'type' => sprintf('in:%s', $types),
'iban' => ['iban', 'nullable', new UniqueIban($account, $this->convertString('type'))],
'bic' => 'bic|nullable',
'account_number' => ['between:1,255', 'nullable', new UniqueAccountNumber($account, $this->convertString('type'))],
'account_number' => ['min:1', 'max:255', 'nullable', new UniqueAccountNumber($account, $this->convertString('type'))],
'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
'opening_balance_date' => 'date|required_with:opening_balance|nullable',
'virtual_balance' => 'numeric|nullable',
@@ -105,7 +105,7 @@ class UpdateRequest extends FormRequest
'monthly_payment_date' => 'date|nullable|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull',
'liability_type' => 'required_if:type,liability|in:loan,debt,mortgage',
'liability_direction' => 'required_if:type,liability|in:credit,debit',
'interest' => 'required_if:type,liability|between:0,100|numeric',
'interest' => 'required_if:type,liability|min:0|max:100|numeric',
'interest_period' => 'required_if:type,liability|in:daily,monthly,yearly',
'notes' => 'min:0|max:65536',
];

View File

@@ -66,9 +66,9 @@ class StoreRequest extends FormRequest
$model = $this->convertString('attachable_type');
return [
'filename' => 'required|between:1,255',
'title' => 'between:1,255',
'notes' => 'between:1,65000',
'filename' => 'required|min:1|max:255',
'title' => ['min:1', 'max:255'],
'notes' => 'min:1|max:32768',
'attachable_type' => sprintf('required|in:%s', $models),
'attachable_id' => ['required', 'numeric', new IsValidAttachmentModel($model)],
];

View File

@@ -68,9 +68,9 @@ class UpdateRequest extends FormRequest
$model = $this->convertString('attachable_type');
return [
'filename' => 'between:1,255',
'title' => 'between:1,255',
'notes' => 'between:1,65000',
'filename' => ['min:1', 'max:255'],
'title' => ['min:1', 'max:255'],
'notes' => 'min:1|max:32768',
'attachable_type' => sprintf('in:%s', $models),
'attachable_id' => ['numeric', new IsValidAttachmentModel($model)],
];

View File

@@ -72,7 +72,7 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'between:1,255|uniqueObjectForUser:bills,name',
'name' => 'min:1|max:255|uniqueObjectForUser:bills,name',
'amount_min' => ['required', new IsValidPositiveAmount()],
'amount_max' => ['required', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id',
@@ -81,9 +81,9 @@ class StoreRequest extends FormRequest
'end_date' => 'date|after:date',
'extension_date' => 'date|after:date',
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly|required',
'skip' => 'between:0,31',
'skip' => 'min:0|max:31|numeric',
'active' => [new IsBoolean()],
'notes' => 'between:1,65536',
'notes' => 'min:1|max:32768',
];
}

View File

@@ -75,7 +75,7 @@ class UpdateRequest extends FormRequest
$bill = $this->route()->parameter('bill');
return [
'name' => sprintf('between:1,255|uniqueObjectForUser:bills,name,%d', $bill->id),
'name' => sprintf('min:1|max:255|uniqueObjectForUser:bills,name,%d', $bill->id),
'amount_min' => ['nullable', new IsValidPositiveAmount()],
'amount_max' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id',
@@ -84,9 +84,9 @@ class UpdateRequest extends FormRequest
'end_date' => 'date|after:date',
'extension_date' => 'date|after:date',
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'between:0,31',
'skip' => 'min:0|max:31|numeric',
'active' => [new IsBoolean()],
'notes' => 'between:1,65536',
'notes' => 'min:1|max:32768',
];
}

View File

@@ -68,11 +68,11 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name',
'name' => 'required|min:1|max:255|uniqueObjectForUser:budgets,name',
'active' => [new IsBoolean()],
'currency_id' => 'exists:transaction_currencies,id',
'currency_code' => 'exists:transaction_currencies,code',
'notes' => 'nullable|between:1,65536',
'notes' => 'nullable|min:1|max:32768',
// auto budget info
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
'auto_budget_amount' => ['required_if:auto_budget_type,reset', 'required_if:auto_budget_type,rollover', 'required_if:auto_budget_type,adjusted', new IsValidPositiveAmount()],

View File

@@ -81,9 +81,9 @@ class UpdateRequest extends FormRequest
$budget = $this->route()->parameter('budget');
return [
'name' => sprintf('between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id),
'name' => sprintf('min:1|max:100|uniqueObjectForUser:budgets,name,%d', $budget->id),
'active' => [new IsBoolean()],
'notes' => 'nullable|between:1,65536',
'notes' => 'nullable|min:1|max:32768',
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_currency_code' => 'exists:transaction_currencies,code',

View File

@@ -70,9 +70,7 @@ class UpdateRequest extends FormRequest
/**
* Configure the validator instance with special rules for after the basic validation rules.
*
* @param Validator $validator
* TODO duplicate code
* TODO duplicate code.
*/
public function withValidator(Validator $validator): void
{
@@ -84,7 +82,7 @@ class UpdateRequest extends FormRequest
$start = new Carbon($data['start']);
$end = new Carbon($data['end']);
if ($end->isBefore($start)) {
$validator->errors()->add('end', (string)trans('validation.date_after'));
$validator->errors()->add('end', (string) trans('validation.date_after'));
}
}
}

View File

@@ -52,7 +52,7 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,100|uniqueObjectForUser:categories,name',
'name' => 'required|min:1|max:100|uniqueObjectForUser:categories,name',
];
}
}

View File

@@ -58,7 +58,7 @@ class UpdateRequest extends FormRequest
$category = $this->route()->parameter('category');
return [
'name' => sprintf('between:1,100|uniqueObjectForUser:categories,name,%d', $category->id),
'name' => sprintf('min:1|max:100|uniqueObjectForUser:categories,name,%d', $category->id),
];
}
}

View File

@@ -64,11 +64,11 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,255|uniquePiggyBankForUser',
'name' => 'required|min:1|max:255|uniquePiggyBankForUser',
'current_amount' => ['nullable', new IsValidPositiveAmount()],
'account_id' => 'required|numeric|belongsToUser:accounts,id',
'object_group_id' => 'numeric|belongsToUser:object_groups,id',
'object_group_title' => 'between:1,255',
'object_group_title' => ['min:1', 'max:255'],
'target_amount' => ['required', new IsValidPositiveAmount()],
'start_date' => 'date|nullable',
'target_date' => 'date|nullable|after:start_date',

View File

@@ -69,7 +69,7 @@ class UpdateRequest extends FormRequest
$piggyBank = $this->route()->parameter('piggyBank');
return [
'name' => 'between:1,255|uniquePiggyBankForUser:'.$piggyBank->id,
'name' => 'min:1|max:255|uniquePiggyBankForUser:'.$piggyBank->id,
'current_amount' => ['nullable', new LessThanPiggyTarget(), new IsValidPositiveAmount()],
'target_amount' => ['nullable', new IsValidPositiveAmount()],
'start_date' => 'date|nullable',

View File

@@ -79,20 +79,20 @@ class StoreRequest extends FormRequest
{
return [
'type' => 'required|in:withdrawal,transfer,deposit',
'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title',
'description' => 'between:1,65000',
'title' => 'required|min:1|max:255|uniqueObjectForUser:recurrences,title',
'description' => 'min:1|max:32768',
'first_date' => 'required|date',
'apply_rules' => [new IsBoolean()],
'active' => [new IsBoolean()],
'repeat_until' => 'nullable|date',
'nr_of_repetitions' => 'nullable|numeric|between:1,31',
'nr_of_repetitions' => 'nullable|numeric|min:1|max:31',
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'nullable|numeric|between:0,31',
'repetitions.*.moment' => 'min:0|max:10',
'repetitions.*.skip' => 'nullable|numeric|min:0|max:31',
'repetitions.*.weekend' => 'numeric|min:1|max:4',
'transactions.*.description' => 'required|between:1,255',
'transactions.*.description' => 'required|min:1|max:255',
'transactions.*.amount' => ['required', new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()],
'transactions.*.currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
@@ -100,18 +100,18 @@ class StoreRequest extends FormRequest
'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
'transactions.*.foreign_currency_code' => 'nullable|min:3|max:51|exists:transaction_currencies,code',
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.source_name' => 'min:1|max:255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.destination_name' => 'min:1|max:255|nullable',
// new and updated fields:
'transactions.*.budget_id' => ['nullable', 'mustExist:budgets,id', new BelongsUser()],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.budget_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.category_id' => ['nullable', 'mustExist:categories,id', new BelongsUser()],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.category_name' => 'min:1|max:255|nullable',
'transactions.*.piggy_bank_id' => ['nullable', 'numeric', 'mustExist:piggy_banks,id', new BelongsUser()],
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.tags' => 'nullable|between:1,255',
'transactions.*.piggy_bank_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.tags' => 'nullable|min:1|max:255',
];
}

View File

@@ -86,20 +86,20 @@ class UpdateRequest extends FormRequest
$recurrence = $this->route()->parameter('recurrence');
return [
'title' => sprintf('between:1,255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id),
'description' => 'between:1,65000',
'title' => sprintf('min:1|max:255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id),
'description' => 'min:1|max:32768',
'first_date' => 'date',
'apply_rules' => [new IsBoolean()],
'active' => [new IsBoolean()],
'repeat_until' => 'nullable|date',
'nr_of_repetitions' => 'nullable|numeric|between:1,31',
'nr_of_repetitions' => 'nullable|numeric|min:1|max:31',
'repetitions.*.type' => 'in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'nullable|numeric|between:0,31',
'repetitions.*.moment' => 'min:0|max:10|numeric',
'repetitions.*.skip' => 'nullable|numeric|min:0|max:31',
'repetitions.*.weekend' => 'nullable|numeric|min:1|max:4',
'transactions.*.description' => 'between:1,255',
'transactions.*.description' => ['min:1', 'max:255'],
'transactions.*.amount' => [new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()],
'transactions.*.currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
@@ -107,18 +107,18 @@ class UpdateRequest extends FormRequest
'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
'transactions.*.foreign_currency_code' => 'nullable|min:3|max:51|exists:transaction_currencies,code',
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.source_name' => 'min:1|max:255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.destination_name' => 'min:1|max:255|nullable',
// new and updated fields:
'transactions.*.budget_id' => ['nullable', 'mustExist:budgets,id', new BelongsUser()],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.budget_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.category_id' => ['nullable', 'mustExist:categories,id', new BelongsUser()],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.category_name' => 'min:1|max:255|nullable',
'transactions.*.piggy_bank_id' => ['nullable', 'numeric', 'mustExist:piggy_banks,id', new BelongsUser()],
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.tags' => 'nullable|between:1,255',
'transactions.*.piggy_bank_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.tags' => 'nullable|min:1|max:255',
];
}

View File

@@ -76,10 +76,10 @@ class StoreRequest extends FormRequest
$contextActions = implode(',', config('firefly.context-rule-actions'));
return [
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
'description' => 'between:1,5000|nullable',
'title' => 'required|min:1|max:100|uniqueObjectForUser:rules,title',
'description' => 'min:1|max:32768|nullable',
'rule_group_id' => 'belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|between:1,255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'rule_group_title' => 'nullable|min:1|max:255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024',

View File

@@ -85,10 +85,10 @@ class UpdateRequest extends FormRequest
$contextActions = implode(',', config('firefly.context-rule-actions'));
return [
'title' => sprintf('between:1,100|uniqueObjectForUser:rules,title,%d', $rule->id),
'description' => 'between:1,5000|nullable',
'title' => sprintf('min:1|max:100|uniqueObjectForUser:rules,title,%d', $rule->id),
'description' => 'min:1|max:32768|nullable',
'rule_group_id' => 'belongsToUser:rule_groups',
'rule_group_title' => 'nullable|between:1,255|belongsToUser:rule_groups,title',
'rule_group_title' => 'nullable|min:1|max:255|belongsToUser:rule_groups,title',
'trigger' => 'in:store-journal,update-journal',
'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024',
@@ -101,7 +101,7 @@ class UpdateRequest extends FormRequest
'strict' => [new IsBoolean()],
'stop_processing' => [new IsBoolean()],
'active' => [new IsBoolean()],
'order' => 'numeric|between:1,1337',
'order' => 'numeric|min:1|max:2048',
];
}

View File

@@ -64,8 +64,8 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'title' => 'required|between:1,100|uniqueObjectForUser:rule_groups,title',
'description' => 'between:1,5000|nullable',
'title' => 'required|min:1|max:100|uniqueObjectForUser:rule_groups,title',
'description' => 'min:1|max:32768|nullable',
'active' => [new IsBoolean()],
];
}

View File

@@ -62,8 +62,8 @@ class UpdateRequest extends FormRequest
$ruleGroup = $this->route()->parameter('ruleGroup');
return [
'title' => 'between:1,100|uniqueObjectForUser:rule_groups,title,'.$ruleGroup->id,
'description' => 'between:1,5000|nullable',
'title' => 'min:1|max:100|uniqueObjectForUser:rule_groups,title,'.$ruleGroup->id,
'description' => 'min:1|max:32768|nullable',
'active' => [new IsBoolean()],
];
}

View File

@@ -28,6 +28,7 @@ use FireflyIII\Rules\BelongsUser;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsDateOrTime;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
use FireflyIII\Support\NullArrayObject;
use FireflyIII\Support\Request\AppendsLocationData;
use FireflyIII\Support\Request\ChecksLogin;
@@ -77,7 +78,7 @@ class StoreRequest extends FormRequest
return [
// basic fields for group:
'group_title' => 'between:1,1000|nullable',
'group_title' => 'min:1|max:1000|nullable',
'error_if_duplicate_hash' => [new IsBoolean()],
'apply_rules' => [new IsBoolean()],
@@ -94,40 +95,40 @@ class StoreRequest extends FormRequest
// amount
'transactions.*.amount' => ['required', new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidZeroOrMoreAmount()],
// description
'transactions.*.description' => 'nullable|between:1,1000',
'transactions.*.description' => 'nullable|min:1|max:1000',
// source of transaction
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.source_iban' => 'between:1,255|nullable|iban',
'transactions.*.source_number' => 'between:1,255|nullable',
'transactions.*.source_bic' => 'between:1,255|nullable|bic',
'transactions.*.source_name' => 'min:1|max:255|nullable',
'transactions.*.source_iban' => 'min:1|max:255|nullable|iban',
'transactions.*.source_number' => 'min:1|max:255|nullable',
'transactions.*.source_bic' => 'min:1|max:255|nullable|bic',
// destination of transaction
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.destination_iban' => 'between:1,255|nullable|iban',
'transactions.*.destination_number' => 'between:1,255|nullable',
'transactions.*.destination_bic' => 'between:1,255|nullable|bic',
'transactions.*.destination_name' => 'min:1|max:255|nullable',
'transactions.*.destination_iban' => 'min:1|max:255|nullable|iban',
'transactions.*.destination_number' => 'min:1|max:255|nullable',
'transactions.*.destination_bic' => 'min:1|max:255|nullable|bic',
// budget, category, bill and piggy
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser()],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.budget_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser(), 'nullable'],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.category_name' => 'min:1|max:255|nullable',
'transactions.*.bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUser()],
'transactions.*.bill_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.bill_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.piggy_bank_id' => ['numeric', 'nullable', 'mustExist:piggy_banks,id', new BelongsUser()],
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.piggy_bank_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
// other interesting fields
'transactions.*.reconciled' => [new IsBoolean()],
'transactions.*.notes' => 'min:1|max:50000|nullable',
'transactions.*.tags' => 'between:0,255',
'transactions.*.tags.*' => 'between:0,255',
'transactions.*.notes' => 'min:1|max:32768|nullable',
'transactions.*.tags' => 'min:0|max:255',
'transactions.*.tags.*' => 'min:0|max:255',
// meta info fields
'transactions.*.internal_reference' => 'min:1|max:255|nullable',

View File

@@ -30,6 +30,7 @@ use FireflyIII\Rules\BelongsUser;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsDateOrTime;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\Validation\GroupValidation;
@@ -98,7 +99,7 @@ class UpdateRequest extends FormRequest
return [
// basic fields for group:
'group_title' => 'between:1,1000|nullable',
'group_title' => 'min:1|max:1000|nullable',
'apply_rules' => [new IsBoolean()],
// transaction rules (in array for splits):
@@ -117,32 +118,32 @@ class UpdateRequest extends FormRequest
// amount
'transactions.*.amount' => ['nullable', new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidZeroOrMoreAmount()],
// description
'transactions.*.description' => 'nullable|between:1,1000',
'transactions.*.description' => 'nullable|min:1|max:1000',
// source of transaction
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.source_name' => 'min:1|max:255|nullable',
// destination of transaction
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser()],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.destination_name' => 'min:1|max:255|nullable',
// budget, category, bill and piggy
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser(), 'nullable'],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.budget_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser(), 'nullable'],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.category_name' => 'min:1|max:255|nullable',
'transactions.*.bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUser()],
'transactions.*.bill_name' => ['between:1,255', 'nullable', new BelongsUser()],
'transactions.*.bill_name' => ['min:1', 'max:255', 'nullable', new BelongsUser()],
// other interesting fields
'transactions.*.reconciled' => [new IsBoolean()],
'transactions.*.notes' => 'min:1|max:50000|nullable',
'transactions.*.tags' => 'between:0,255|nullable',
'transactions.*.tags.*' => 'between:0,255',
'transactions.*.notes' => 'min:1|max:32768|nullable',
'transactions.*.tags' => 'min:0|max:255|nullable',
'transactions.*.tags.*' => 'min:0|max:255',
// meta info fields
'transactions.*.internal_reference' => 'min:1|max:255|nullable',

View File

@@ -66,10 +66,10 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,255|unique:transaction_currencies,name',
'code' => 'required|between:3,51|unique:transaction_currencies,code',
'symbol' => 'required|between:1,51|unique:transaction_currencies,symbol',
'decimal_places' => 'between:0,20|numeric|min:0|max:12',
'name' => 'required|min:1|max:255|unique:transaction_currencies,name',
'code' => 'required|min:3|max:32|unique:transaction_currencies,code',
'symbol' => 'required|min:1|max:32|unique:transaction_currencies,symbol',
'decimal_places' => 'numeric|min:0|max:12',
'enabled' => [new IsBoolean()],
'default' => [new IsBoolean()],
];

View File

@@ -64,10 +64,10 @@ class UpdateRequest extends FormRequest
$currency = $this->route()->parameter('currency_code');
return [
'name' => sprintf('between:1,255|unique:transaction_currencies,name,%d', $currency->id),
'code' => sprintf('between:3,51|unique:transaction_currencies,code,%d', $currency->id),
'symbol' => sprintf('between:1,51|unique:transaction_currencies,symbol,%d', $currency->id),
'decimal_places' => 'between:0,20|numeric|min:0|max:12',
'name' => sprintf('min:1|max:255|unique:transaction_currencies,name,%d', $currency->id),
'code' => sprintf('min:3|max:32|unique:transaction_currencies,code,%d', $currency->id),
'symbol' => sprintf('min:1|max:32|unique:transaction_currencies,symbol,%d', $currency->id),
'decimal_places' => 'numeric|min:0|max:12',
'enabled' => [new IsBoolean()],
'default' => [new IsBoolean()],
];

View File

@@ -63,7 +63,7 @@ class StoreRequest extends FormRequest
'link_type_name' => 'exists:link_types,name|required_without:link_type_id',
'inward_id' => 'required|belongsToUser:transaction_journals,id|different:outward_id',
'outward_id' => 'required|belongsToUser:transaction_journals,id|different:inward_id',
'notes' => 'between:0,65000',
'notes' => 'min:1|max:32768|nullable',
];
}

View File

@@ -63,7 +63,7 @@ class UpdateRequest extends FormRequest
'link_type_name' => 'exists:link_types,name',
'inward_id' => 'belongsToUser:transaction_journals,id|different:outward_id',
'outward_id' => 'belongsToUser:transaction_journals,id|different:inward_id',
'notes' => 'between:0,65000',
'notes' => 'min:1|max:32768|nullable',
];
}

View File

@@ -72,7 +72,7 @@ class CreateRequest extends FormRequest
$validProtocols = config('firefly.valid_url_protocols');
return [
'title' => 'required|between:1,512|uniqueObjectForUser:webhooks,title',
'title' => 'required|min:1|max:255|uniqueObjectForUser:webhooks,title',
'active' => [new IsBoolean()],
'trigger' => sprintf('required|in:%s', $triggers),
'response' => sprintf('required|in:%s', $responses),

View File

@@ -85,7 +85,7 @@ class UpdateRequest extends FormRequest
$webhook = $this->route()->parameter('webhook');
return [
'title' => sprintf('between:1,512|uniqueObjectForUser:webhooks,title,%d', $webhook->id),
'title' => sprintf('min:1|max:255|uniqueObjectForUser:webhooks,title,%d', $webhook->id),
'active' => [new IsBoolean()],
'trigger' => sprintf('in:%s', $triggers),
'response' => sprintf('in:%s', $responses),

View File

@@ -65,7 +65,7 @@ class UpdateRequest extends FormRequest
return ['value' => ['required', new IsBoolean()]];
}
if ('configuration.permission_update_check' === $name) {
return ['value' => 'required|numeric|between:-1,1'];
return ['value' => 'required|numeric|min:-1|max:1'];
}
if ('configuration.last_update_check' === $name) {
return ['value' => 'required|numeric|min:464272080'];

View File

@@ -77,11 +77,7 @@ class BudgetController extends Controller
}
/**
* @param DateRequest $request
*
* TODO see autocomplete/accountcontroller
*
* @throws FireflyException
*/
public function dashboard(DateRequest $request): JsonResponse
{

View File

@@ -0,0 +1,43 @@
<?php
/*
* ShowController.php
* Copyright (c) 2024 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\Transaction;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Transformers\V2\TransactionGroupTransformer;
use Illuminate\Http\JsonResponse;
class ShowController extends Controller
{
/**
* TODO this endpoint is not yet reachable.
*/
public function show(TransactionGroup $transactionGroup): JsonResponse
{
$transformer = new TransactionGroupTransformer();
$transformer->setParameters($this->parameters);
return response()->api($this->jsonApiObject('transactions', $transactionGroup, $transformer))->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -28,6 +28,7 @@ use FireflyIII\Models\UserGroup;
use FireflyIII\Rules\BelongsUserGroup;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsDateOrTime;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\NullArrayObject;
use FireflyIII\Support\Request\AppendsLocationData;
use FireflyIII\Support\Request\ChecksLogin;
@@ -74,7 +75,6 @@ class StoreRequest extends FormRequest
'fire_webhooks' => $this->boolean('fire_webhooks', true),
'transactions' => $this->getTransactionData(),
];
// TODO include location and ability to process it.
}
/**
@@ -91,81 +91,84 @@ class StoreRequest extends FormRequest
return [
// basic fields for group:
'group_title' => 'between:1,1000|nullable',
'error_if_duplicate_hash' => [new IsBoolean()],
'apply_rules' => [new IsBoolean()],
'group_title' => 'min:1|max:1000|nullable',
'error_if_duplicate_hash' => [new IsBoolean()],
'apply_rules' => [new IsBoolean()],
// transaction rules (in array for splits):
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
'transactions.*.date' => ['required', new IsDateOrTime()],
'transactions.*.order' => 'numeric|min:0',
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
'transactions.*.date' => ['required', new IsDateOrTime()],
'transactions.*.order' => 'numeric|min:0',
// currency info
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
'transactions.*.currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
'transactions.*.foreign_currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
'transactions.*.currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
'transactions.*.foreign_currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
// amount
'transactions.*.amount' => 'required|numeric|gt:0|max:1000000000',
'transactions.*.foreign_amount' => 'numeric|gt:0|max:1000000000',
'transactions.*.amount' => ['required', new IsValidPositiveAmount()],
'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()],
// description
'transactions.*.description' => 'nullable|between:1,1000',
'transactions.*.description' => 'nullable|min:1|max:1000',
// source of transaction
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.source_iban' => 'between:1,255|nullable|iban',
'transactions.*.source_number' => 'between:1,255|nullable',
'transactions.*.source_bic' => 'between:1,255|nullable|bic',
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.source_name' => 'min:1|max:255|nullable',
'transactions.*.source_iban' => 'min:1|max:255|nullable|iban',
'transactions.*.source_number' => 'min:1|max:255|nullable',
'transactions.*.source_bic' => 'min:1|max:255|nullable|bic',
// destination of transaction
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.destination_iban' => 'between:1,255|nullable|iban',
'transactions.*.destination_number' => 'between:1,255|nullable',
'transactions.*.destination_bic' => 'between:1,255|nullable|bic',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.destination_name' => 'min:1|max:255|nullable',
'transactions.*.destination_iban' => 'min:1|max:255|nullable|iban',
'transactions.*.destination_number' => 'min:1|max:255|nullable',
'transactions.*.destination_bic' => 'min:1|max:255|nullable|bic',
// budget, category, bill and piggy
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUserGroup($userGroup)],
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUserGroup($userGroup), 'nullable'],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUserGroup($userGroup)],
'transactions.*.bill_name' => ['between:1,255', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.piggy_bank_id' => ['numeric', 'nullable', 'mustExist:piggy_banks,id', new BelongsUserGroup($userGroup)],
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUserGroup($userGroup)],
'transactions.*.budget_name' => ['min:1', 'max:255', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUserGroup($userGroup), 'nullable'],
'transactions.*.category_name' => 'min:1|max:255|nullable',
'transactions.*.bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUserGroup($userGroup)],
'transactions.*.bill_name' => ['min:1', 'max:255', 'nullable', new BelongsUserGroup($userGroup)],
'transactions.*.piggy_bank_id' => ['numeric', 'nullable', 'mustExist:piggy_banks,id', new BelongsUserGroup($userGroup)],
'transactions.*.piggy_bank_name' => ['min:1', 'max:255', 'nullable', new BelongsUserGroup($userGroup)],
// other interesting fields
'transactions.*.reconciled' => [new IsBoolean()],
'transactions.*.notes' => 'min:1|max:50000|nullable',
'transactions.*.tags' => 'between:0,255',
'transactions.*.reconciled' => [new IsBoolean()],
'transactions.*.notes' => 'min:1|max:32768|nullable',
'transactions.*.tags' => 'min:0|max:255',
'transactions.*.tags.*' => 'min:0|max:255',
// meta info fields
'transactions.*.internal_reference' => 'min:1|max:255|nullable',
'transactions.*.external_id' => 'min:1|max:255|nullable',
'transactions.*.recurrence_id' => 'min:1|max:255|nullable',
'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable',
'transactions.*.external_url' => 'min:1|max:255|nullable|url',
'transactions.*.internal_reference' => 'min:1|max:255|nullable',
'transactions.*.external_id' => 'min:1|max:255|nullable',
'transactions.*.recurrence_id' => 'min:1|max:255|nullable',
'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable',
'transactions.*.external_url' => 'min:1|max:255|nullable|url',
// SEPA fields:
'transactions.*.sepa_cc' => 'min:1|max:255|nullable',
'transactions.*.sepa_ct_op' => 'min:1|max:255|nullable',
'transactions.*.sepa_ct_id' => 'min:1|max:255|nullable',
'transactions.*.sepa_db' => 'min:1|max:255|nullable',
'transactions.*.sepa_country' => 'min:1|max:255|nullable',
'transactions.*.sepa_ep' => 'min:1|max:255|nullable',
'transactions.*.sepa_ci' => 'min:1|max:255|nullable',
'transactions.*.sepa_batch_id' => 'min:1|max:255|nullable',
'transactions.*.sepa_cc' => 'min:1|max:255|nullable',
'transactions.*.sepa_ct_op' => 'min:1|max:255|nullable',
'transactions.*.sepa_ct_id' => 'min:1|max:255|nullable',
'transactions.*.sepa_db' => 'min:1|max:255|nullable',
'transactions.*.sepa_country' => 'min:1|max:255|nullable',
'transactions.*.sepa_ep' => 'min:1|max:255|nullable',
'transactions.*.sepa_ci' => 'min:1|max:255|nullable',
'transactions.*.sepa_batch_id' => 'min:1|max:255|nullable',
// dates
'transactions.*.interest_date' => 'date|nullable',
'transactions.*.book_date' => 'date|nullable',
'transactions.*.process_date' => 'date|nullable',
'transactions.*.due_date' => 'date|nullable',
'transactions.*.payment_date' => 'date|nullable',
'transactions.*.invoice_date' => 'date|nullable',
'transactions.*.interest_date' => 'date|nullable',
'transactions.*.book_date' => 'date|nullable',
'transactions.*.process_date' => 'date|nullable',
'transactions.*.due_date' => 'date|nullable',
'transactions.*.payment_date' => 'date|nullable',
'transactions.*.invoice_date' => 'date|nullable',
// TODO include location and ability to process it.
];
}
@@ -222,7 +225,7 @@ class StoreRequest extends FormRequest
*/
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
$result = [
'type' => $this->clearString($object['type']),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']),
@@ -300,6 +303,8 @@ class StoreRequest extends FormRequest
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
];
$result = $this->addFromromTransactionStore($transaction, $result);
$return[] = $result;
}
return $return;

View File

@@ -49,7 +49,7 @@ class StoreRequest extends FormRequest
public function rules(): array
{
return [
'title' => 'unique:user_groups,title|required|min:2|max:255',
'title' => 'unique:user_groups,title|required|min:1|max:255',
];
}
}

View File

@@ -53,7 +53,7 @@ class UpdateRequest extends FormRequest
$userGroup = $this->route()->parameter('userGroup');
return [
'title' => sprintf('required|min:2|max:255|unique:user_groups,title,%d', $userGroup->id),
'title' => sprintf('required|min:1|max:255|unique:user_groups,title,%d', $userGroup->id),
];
}
}

View File

@@ -216,6 +216,7 @@ class Handler extends ExceptionHandler
'json' => request()->acceptsJson(),
'method' => request()->method(),
'headers' => $headers,
'post' => 'POST' === request()->method() ? json_encode(request()->all()) : '',
];
// create job that will mail.

View File

@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Location;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
@@ -49,6 +50,8 @@ use Illuminate\Support\Collection;
/**
* Class TransactionJournalFactory
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class TransactionJournalFactory
{
@@ -318,10 +321,23 @@ class TransactionJournalFactory
$this->storePiggyEvent($journal, $row);
$this->storeTags($journal, $row['tags']);
$this->storeMetaFields($journal, $row);
$this->storeLocation($journal, $row);
return $journal;
}
private function storeLocation(TransactionJournal $journal, NullArrayObject $data): void
{
if (true === $data['store_location']) {
$location = new Location();
$location->longitude = $data['longitude'];
$location->latitude = $data['latitude'];
$location->zoom_level = $data['zoom_level'];
$location->locatable()->associate($journal);
$location->save();
}
}
private function hashArray(NullArrayObject $row): string
{
$dataRow = $row->getArrayCopy();
@@ -360,16 +376,13 @@ class TransactionJournalFactory
->where('transaction_journals.user_id', $this->user->id)
->where('data', json_encode($hash, JSON_THROW_ON_ERROR))
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
->first()
->first(['journal_meta.*'])
;
if (null !== $result) {
app('log')->warning(sprintf('Found a duplicate in errorIfDuplicate because hash %s is not unique!', $hash));
$journal = $result->transactionJournal()->withTrashed()->first();
$group = $journal?->transactionGroup()->withTrashed()->first();
$groupId = $group?->id;
if (null === $group) {
$groupId = 0;
}
$groupId = (int) $group?->id;
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $groupId));
}

View File

@@ -462,7 +462,7 @@ trait TimeCollection
*/
public function setBefore(Carbon $date): GroupCollectorInterface
{
$beforeStr = $date->format('Y-m-d 00:00:00');
$beforeStr = $date->format('Y-m-d 23:59:59');
$this->query->where('transaction_journals.date', '<=', $beforeStr);
return $this;

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Helpers\Collector;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\Extensions\AccountCollection;
use FireflyIII\Helpers\Collector\Extensions\AmountCollection;
@@ -106,6 +105,8 @@ class GroupCollector implements GroupCollectorInterface
'transaction_groups.created_at as created_at',
'transaction_groups.updated_at as updated_at',
'transaction_groups.title as transaction_group_title',
'transaction_groups.created_at as group_created_at',
'transaction_groups.updated_at as group_updated_at',
// journal
'transaction_journals.id as transaction_journal_id',
@@ -285,7 +286,7 @@ class GroupCollector implements GroupCollectorInterface
foreach ($params as $param) {
$replace = sprintf('"%s"', $param);
if (is_int($param)) {
$replace = (string)$param;
$replace = (string) $param;
}
$pos = strpos($query, '?');
if (false !== $pos) {
@@ -691,24 +692,26 @@ class GroupCollector implements GroupCollectorInterface
/** @var TransactionJournal $augumentedJournal */
foreach ($collection as $augumentedJournal) {
$groupId = (int)$augumentedJournal->transaction_group_id;
$groupId = (int) $augumentedJournal->transaction_group_id;
if (!array_key_exists($groupId, $groups)) {
// make new array
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
$groupArray = [
'id' => (int)$augumentedJournal->transaction_group_id,
'id' => (int) $augumentedJournal->transaction_group_id,
'user_id' => $augumentedJournal->user_id,
'user_group_id' => $augumentedJournal->user_group_id,
// Field transaction_group_title was added by the query.
'title' => $augumentedJournal->transaction_group_title, // @phpstan-ignore-line
'created_at' => new Carbon($augumentedJournal->group_created_at, config('app.timezone')),
'updated_at' => new Carbon($augumentedJournal->group_updated_at, config('app.timezone')),
'transaction_type' => $parsedGroup['transaction_type_type'],
'count' => 1,
'sums' => [],
'transactions' => [],
];
// Field transaction_journal_id was added by the query.
$journalId = (int)$augumentedJournal->transaction_journal_id; // @phpstan-ignore-line
$journalId = (int) $augumentedJournal->transaction_journal_id; // @phpstan-ignore-line
$groupArray['transactions'][$journalId] = $parsedGroup;
$groups[$groupId] = $groupArray;
@@ -716,7 +719,7 @@ class GroupCollector implements GroupCollectorInterface
}
// or parse the rest.
// Field transaction_journal_id was added by the query.
$journalId = (int)$augumentedJournal->transaction_journal_id; // @phpstan-ignore-line
$journalId = (int) $augumentedJournal->transaction_journal_id; // @phpstan-ignore-line
if (array_key_exists($journalId, $groups[$groupId]['transactions'])) {
// append data to existing group + journal (for multiple tags or multiple attachments)
$groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
@@ -769,7 +772,7 @@ class GroupCollector implements GroupCollectorInterface
$dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date'];
if (array_key_exists('meta_name', $result) && in_array($result['meta_name'], $dates, true)) {
$name = $result['meta_name'];
if (array_key_exists('meta_data', $result) && '' !== (string)$result['meta_data']) {
if (array_key_exists('meta_data', $result) && '' !== (string) $result['meta_data']) {
$result[$name] = Carbon::createFromFormat('!Y-m-d', substr(json_decode($result['meta_data']), 0, 10));
}
}
@@ -780,9 +783,9 @@ class GroupCollector implements GroupCollectorInterface
// convert back to strings because SQLite is dumb like that.
$result = $this->convertToStrings($result);
$result['reconciled'] = 1 === (int)$result['reconciled'];
$result['reconciled'] = 1 === (int) $result['reconciled'];
if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well.
$tagId = (int)$augumentedJournal['tag_id'];
$tagId = (int) $augumentedJournal['tag_id'];
$tagDate = null;
try {
@@ -792,7 +795,7 @@ class GroupCollector implements GroupCollectorInterface
}
$result['tags'][$tagId] = [
'id' => (int)$result['tag_id'],
'id' => (int) $result['tag_id'],
'name' => $result['tag_name'],
'date' => $tagDate,
'description' => $result['tag_description'],
@@ -801,8 +804,8 @@ class GroupCollector implements GroupCollectorInterface
// also merge attachments:
if (array_key_exists('attachment_id', $result)) {
$uploaded = 1 === (int)$result['attachment_uploaded'];
$attachmentId = (int)$augumentedJournal['attachment_id'];
$uploaded = 1 === (int) $result['attachment_uploaded'];
$attachmentId = (int) $augumentedJournal['attachment_id'];
if (0 !== $attachmentId && $uploaded) {
$result['attachments'][$attachmentId] = [
'id' => $attachmentId,
@@ -828,7 +831,7 @@ class GroupCollector implements GroupCollectorInterface
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
$array[$field] = array_key_exists($field, $array) ? (int) $array[$field] : null;
}
return $array;
@@ -837,7 +840,7 @@ class GroupCollector implements GroupCollectorInterface
private function convertToStrings(array $array): array
{
foreach ($this->stringFields as $field) {
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string)$array[$field] : null;
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string) $array[$field] : null;
}
return $array;
@@ -847,7 +850,7 @@ class GroupCollector implements GroupCollectorInterface
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int)$newJournal['tag_id'];
$tagId = (int) $newJournal['tag_id'];
$tagDate = null;
@@ -858,7 +861,7 @@ class GroupCollector implements GroupCollectorInterface
}
$existingJournal['tags'][$tagId] = [
'id' => (int)$newArray['tag_id'],
'id' => (int) $newArray['tag_id'],
'name' => $newArray['tag_name'],
'date' => $tagDate,
'description' => $newArray['tag_description'],
@@ -872,7 +875,7 @@ class GroupCollector implements GroupCollectorInterface
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int)$newJournal['attachment_id'];
$attachmentId = (int) $newJournal['attachment_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
@@ -891,7 +894,7 @@ class GroupCollector implements GroupCollectorInterface
foreach ($groups as $groudId => $group) {
/** @var array $transaction */
foreach ($group['transactions'] as $transaction) {
$currencyId = (int)$transaction['currency_id'];
$currencyId = (int) $transaction['currency_id'];
if (null === $transaction['amount']) {
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
}
@@ -907,7 +910,7 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int)$transaction['foreign_currency_id'];
$currencyId = (int) $transaction['foreign_currency_id'];
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
@@ -951,11 +954,11 @@ class GroupCollector implements GroupCollectorInterface
continue;
}
// if the result is a bool, use the unedited results.
if(true === $result) {
if (true === $result) {
$nextCollection->push($item);
}
// if the result is an array, the filter has changed what's being returned.
if(is_array($result)) {
if (is_array($result)) {
$nextCollection->push($result);
}
}

View File

@@ -231,6 +231,7 @@ class CreateController extends Controller
return redirect(route('recurring.create'))->withInput();
}
Log::channel('audit')->info('Stored new recurrence.', $data);
$request->session()->flash('success', (string)trans('firefly.stored_new_recurrence', ['title' => $recurrence->title]));
app('preferences')->mark();

View File

@@ -172,6 +172,7 @@ class EditController extends Controller
$this->recurring->update($recurrence, $data);
$request->session()->flash('success', (string)trans('firefly.updated_recurrence', ['title' => $recurrence->title]));
Log::channel('audit')->info(sprintf('Updated recurrence #%d.', $recurrence->id), $data);
// store new attachment(s):
/** @var null|array $files */

View File

@@ -50,7 +50,7 @@ class CreateController extends Controller
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.transactions'));
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-exchange');
$this->repository = app(TransactionGroupRepositoryInterface::class);
@@ -61,7 +61,7 @@ class CreateController extends Controller
public function cloneGroup(Request $request): JsonResponse
{
$groupId = (int)$request->get('id');
$groupId = (int) $request->get('id');
if (0 !== $groupId) {
$group = $this->repository->find($groupId);
if (null !== $group) {
@@ -101,23 +101,43 @@ class CreateController extends Controller
{
app('preferences')->mark();
$sourceId = (int)request()->get('source');
$destinationId = (int)request()->get('destination');
$sourceId = (int) request()->get('source');
$destinationId = (int) request()->get('destination');
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$cash = $accountRepository->getCashAccount();
$preFilled = session()->has('preFilled') ? session('preFilled') : [];
$subTitle = (string)trans(sprintf('breadcrumbs.create_%s', strtolower((string)$objectType)));
$subTitleIcon = 'fa-plus';
$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();
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
$parts = parse_url($previousUrl);
$search = sprintf('?%s', $parts['query'] ?? '');
$previousUrl = str_replace($search, '', $previousUrl);
$accountRepository = app(AccountRepositoryInterface::class);
$cash = $accountRepository->getCashAccount();
$preFilled = session()->has('preFilled') ? session('preFilled') : [];
$subTitle = (string) trans(sprintf('breadcrumbs.create_%s', strtolower((string) $objectType)));
$subTitleIcon = 'fa-plus';
$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();
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
$parts = parse_url($previousUrl);
$search = sprintf('?%s', $parts['query'] ?? '');
$previousUrl = str_replace($search, '', $previousUrl);
if (!is_array($optionalFields)) {
$optionalFields = [];
}
// not really a fan of this, but meh.
$optionalDateFields = [
'interest_date' => $optionalFields['interest_date'] ?? false,
'book_date' => $optionalFields['book_date'] ?? false,
'process_date' => $optionalFields['process_date'] ?? false,
'due_date' => $optionalFields['due_date'] ?? false,
'payment_date' => $optionalFields['payment_date'] ?? false,
'invoice_date' => $optionalFields['invoice_date'] ?? false,
];
$optionalFields['external_url'] ??= false;
$optionalFields['location'] ??= false;
$optionalFields['location'] = $optionalFields['location'] && true === config('firefly.enable_external_map');
// map info:
$longitude = config('firefly.default_location.longitude');
$latitude = config('firefly.default_location.latitude');
$zoomLevel = config('firefly.default_location.zoom_level');
session()->put('preFilled', $preFilled);
@@ -126,7 +146,11 @@ class CreateController extends Controller
compact(
'subTitleIcon',
'cash',
'longitude',
'latitude',
'zoomLevel',
'objectType',
'optionalDateFields',
'subTitle',
'defaultCurrency',
'previousUrl',

View File

@@ -51,7 +51,7 @@ class EditController extends Controller
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.transactions'));
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-exchange');
$this->repository = app(JournalRepositoryInterface::class);
@@ -73,18 +73,43 @@ class EditController extends Controller
}
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
$accountToTypes = config('firefly.account_to_transaction');
$expectedSourceTypes = config('firefly.expected_source_types');
$allowedSourceDests = config('firefly.source_dests');
$repository = app(AccountRepositoryInterface::class);
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
$accountToTypes = config('firefly.account_to_transaction');
$expectedSourceTypes = config('firefly.expected_source_types');
$allowedSourceDests = config('firefly.source_dests');
$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();
$cash = $repository->getCashAccount();
$previousUrl = $this->rememberPreviousUrl('transactions.edit.url');
$parts = parse_url($previousUrl);
$search = sprintf('?%s', $parts['query'] ?? '');
$previousUrl = str_replace($search, '', $previousUrl);
$defaultCurrency = app('amount')->getDefaultCurrency();
$cash = $repository->getCashAccount();
$previousUrl = $this->rememberPreviousUrl('transactions.edit.url');
$parts = parse_url($previousUrl);
$search = sprintf('?%s', $parts['query'] ?? '');
$previousUrl = str_replace($search, '', $previousUrl);
// settings necessary for v2
$optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
if (!is_array($optionalFields)) {
$optionalFields = [];
}
// not really a fan of this, but meh.
$optionalDateFields = [
'interest_date' => $optionalFields['interest_date'] ?? false,
'book_date' => $optionalFields['book_date'] ?? false,
'process_date' => $optionalFields['process_date'] ?? false,
'due_date' => $optionalFields['due_date'] ?? false,
'payment_date' => $optionalFields['payment_date'] ?? false,
'invoice_date' => $optionalFields['invoice_date'] ?? false,
];
$optionalFields['external_url'] ??= false;
$optionalFields['location'] ??= false;
$optionalFields['location'] = $optionalFields['location'] && true === config('firefly.enable_external_map');
// map info:
$longitude = config('firefly.default_location.longitude');
$latitude = config('firefly.default_location.latitude');
$zoomLevel = config('firefly.default_location.zoom_level');
return view(
'transactions.edit',
@@ -92,6 +117,13 @@ class EditController extends Controller
'cash',
'allowedSourceDests',
'expectedSourceTypes',
'optionalDateFields',
'longitude',
'latitude',
'zoomLevel',
'optionalFields',
'subTitle',
'subTitleIcon',
'transactionGroup',
'allowedOpposingTypes',
'accountToTypes',

View File

@@ -108,7 +108,7 @@ class AccountFormRequest extends FormRequest
'BIC' => 'bic|nullable',
'virtual_balance' => ['nullable', new IsValidAmount()],
'currency_id' => 'exists:transaction_currencies,id',
'account_number' => 'between:1,255|uniqueAccountNumberForUser|nullable',
'account_number' => 'min:1|max:255|uniqueAccountNumberForUser|nullable',
'account_role' => 'in:'.$accountRoles,
'active' => 'boolean',
'cc_type' => 'in:'.$ccPaymentTypes,
@@ -116,7 +116,7 @@ class AccountFormRequest extends FormRequest
'amount_currency_id_virtual_balance' => 'exists:transaction_currencies,id',
'what' => 'in:'.$types,
'interest_period' => 'in:daily,monthly,yearly',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
$rules = Location::requestRules($rules);

View File

@@ -53,8 +53,8 @@ class AttachmentFormRequest extends FormRequest
{
// fixed
return [
'title' => 'between:1,255|nullable',
'notes' => 'between:1,65536|nullable',
'title' => 'min:1|max:255|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}
}

View File

@@ -64,12 +64,12 @@ class BillStoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,255|uniqueObjectForUser:bills,name',
'name' => 'required|min:1|max:255|uniqueObjectForUser:bills,name',
'amount_min' => ['required', new IsValidPositiveAmount()],
'amount_max' => ['required', new IsValidPositiveAmount()],
'transaction_currency_id' => 'required|exists:transaction_currencies,id',
'date' => 'required|date',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
'bill_end_date' => 'nullable|date',
'extension_date' => 'nullable|date',
'repeat_freq' => sprintf('required|in:%s', implode(',', config('firefly.bill_periods'))),

View File

@@ -68,7 +68,7 @@ class BillUpdateRequest extends FormRequest
$bill = $this->route()->parameter('bill');
return [
'name' => sprintf('required|between:1,255|uniqueObjectForUser:bills,name,%d', $bill->id),
'name' => sprintf('required|min:1|max:255|uniqueObjectForUser:bills,name,%d', $bill->id),
'amount_min' => ['required', new IsValidPositiveAmount()],
'amount_max' => ['required', new IsValidPositiveAmount()],
'transaction_currency_id' => 'required|exists:transaction_currencies,id',
@@ -78,7 +78,7 @@ class BillUpdateRequest extends FormRequest
'repeat_freq' => sprintf('required|in:%s', implode(',', config('firefly.bill_periods'))),
'skip' => 'required|integer|gte:0|lte:31',
'active' => 'boolean',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}
}

View File

@@ -61,13 +61,13 @@ class BudgetFormStoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name',
'active' => 'numeric|between:0,1',
'name' => 'required|min:1|max:255|uniqueObjectForUser:budgets,name',
'active' => 'numeric|min:0|max:1',
'auto_budget_type' => 'numeric|integer|gte:0|lte:3',
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_amount' => ['required_if:auto_budget_type,1', 'required_if:auto_budget_type,2', new IsValidPositiveAmount()],
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}

View File

@@ -60,23 +60,23 @@ class BudgetFormUpdateRequest extends FormRequest
*/
public function rules(): array
{
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name';
$nameRule = 'required|min:1|max:255|uniqueObjectForUser:budgets,name';
/** @var null|Budget $budget */
$budget = $this->route()->parameter('budget');
if (null !== $budget) {
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,'.$budget->id;
$nameRule = 'required|min:1|max:255|uniqueObjectForUser:budgets,name,'.$budget->id;
}
return [
'name' => $nameRule,
'active' => 'numeric|between:0,1',
'active' => 'numeric|min:0|max:1',
'auto_budget_type' => 'numeric|integer|gte:0|lte:31',
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_amount' => ['required_if:auto_budget_type,1', 'required_if:auto_budget_type,2|numeric', new IsValidPositiveAmount()],
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}

View File

@@ -52,19 +52,19 @@ class CategoryFormRequest extends FormRequest
*/
public function rules(): array
{
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name';
$nameRule = 'required|min:1|max:255|uniqueObjectForUser:categories,name';
/** @var null|Category $category */
$category = $this->route()->parameter('category');
if (null !== $category) {
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,'.$category->id;
$nameRule = 'required|min:1|max:255|uniqueObjectForUser:categories,name,'.$category->id;
}
// fixed
return [
'name' => $nameRule,
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}
}

View File

@@ -51,8 +51,8 @@ class ConfigurationRequest extends FormRequest
{
// fixed
return [
'single_user_mode' => 'between:0,1|numeric',
'is_demo_site' => 'between:0,1|numeric',
'single_user_mode' => 'min:0|max:1|numeric',
'is_demo_site' => 'min:0|max:1|numeric',
];
}
}

View File

@@ -43,7 +43,7 @@ class NewUserFormRequest extends FormRequest
{
// fixed
return [
'bank_name' => 'required|between:1,200',
'bank_name' => 'required|min:1|max:255',
'bank_balance' => ['required', new IsValidAmount()],
'savings_balance' => ['nullable', new IsValidAmount()],
'credit_card_limit' => ['nullable', new IsValidAmount()],

View File

@@ -53,10 +53,10 @@ class ObjectGroupFormRequest extends FormRequest
{
/** @var null|ObjectGroup $objectGroup */
$objectGroup = $this->route()->parameter('objectGroup');
$titleRule = 'required|between:1,255|uniqueObjectGroup';
$titleRule = 'required|min:1|max:255|uniqueObjectGroup';
if (null !== $objectGroup) {
$titleRule = sprintf('required|between:1,255|uniqueObjectGroup:%d', $objectGroup->id);
$titleRule = sprintf('required|min:1|max:255|uniqueObjectGroup:%d', $objectGroup->id);
}
return [

View File

@@ -58,14 +58,14 @@ class PiggyBankStoreRequest extends FormRequest
public function rules(): array
{
return [
'name' => 'required|between:1,255|uniquePiggyBankForUser',
'name' => 'required|min:1|max:255|uniquePiggyBankForUser',
'account_id' => 'required|belongsToUser:accounts',
'targetamount' => ['nullable', new IsValidPositiveAmount()],
'startdate' => 'date',
'targetdate' => 'date|nullable',
'order' => 'integer|min:1',
'object_group' => 'min:0|max:255',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}
}

View File

@@ -62,14 +62,14 @@ class PiggyBankUpdateRequest extends FormRequest
$piggy = $this->route()->parameter('piggyBank');
return [
'name' => sprintf('required|between:1,255|uniquePiggyBankForUser:%d', $piggy->id),
'name' => sprintf('required|min:1|max:255|uniquePiggyBankForUser:%d', $piggy->id),
'account_id' => 'required|belongsToUser:accounts',
'targetamount' => ['nullable', new IsValidPositiveAmount()],
'startdate' => 'date',
'targetdate' => 'date|nullable',
'order' => 'integer|max:65536|min:1',
'object_group' => 'min:0|max:255',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
];
}
}

View File

@@ -156,28 +156,29 @@ class RecurrenceFormRequest extends FormRequest
{
$today = today(config('app.timezone'));
$tomorrow = today(config('app.timezone'))->addDay();
$before = today(config('app.timezone'))->addYears(25);
$rules = [
// mandatory info for recurrence.
'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title',
'first_date' => 'required|date|after:'.$today->format('Y-m-d'),
'repetition_type' => ['required', new ValidRecurrenceRepetitionValue(), new ValidRecurrenceRepetitionType(), 'between:1,20'],
'title' => 'required|min:1|max:255|uniqueObjectForUser:recurrences,title',
'first_date' => sprintf('required|date|before:%s|after:%s', $before->format('Y-m-d'), $today->format('Y-m-d')),
'repetition_type' => ['required', new ValidRecurrenceRepetitionValue(), new ValidRecurrenceRepetitionType(), 'min:1', 'max:32'],
'skip' => 'required|numeric|integer|gte:0|lte:31',
'notes' => 'between:1,65536|nullable',
'notes' => 'min:1|max:32768|nullable',
// optional for recurrence:
'recurring_description' => 'between:0,65000',
'active' => 'numeric|between:0,1',
'apply_rules' => 'numeric|between:0,1',
'recurring_description' => 'min:0|max:32768',
'active' => 'numeric|min:0|max:1',
'apply_rules' => 'numeric|min:0|max:1',
// mandatory for transaction:
'transaction_description' => 'required|between:1,255',
'transaction_description' => 'required|min:1|max:255',
'transaction_type' => 'required|in:withdrawal,deposit,transfer',
'transaction_currency_id' => 'required|exists:transaction_currencies,id',
'amount' => ['required', new IsValidPositiveAmount()],
// mandatory account info:
'source_id' => 'numeric|belongsToUser:accounts,id|nullable',
'source_name' => 'between:1,255|nullable',
'source_name' => 'min:1|max:255|nullable',
'destination_id' => 'numeric|belongsToUser:accounts,id|nullable',
'destination_name' => 'between:1,255|nullable',
'destination_name' => 'min:1|max:255|nullable',
// foreign amount data:
'foreign_amount' => ['nullable', new IsValidPositiveAmount()],
@@ -185,8 +186,8 @@ class RecurrenceFormRequest extends FormRequest
// optional fields:
'budget_id' => 'mustExist:budgets,id|belongsToUser:budgets,id|nullable',
'bill_id' => 'mustExist:bills,id|belongsToUser:bills,id|nullable',
'category' => 'between:1,255|nullable',
'tags' => 'between:1,255|nullable',
'category' => 'min:1|max:255|nullable',
'tags' => 'min:1|max:255|nullable',
];
if ($this->convertInteger('foreign_currency_id') > 0) {
$rules['foreign_currency_id'] = 'exists:transaction_currencies,id';
@@ -194,7 +195,7 @@ class RecurrenceFormRequest extends FormRequest
// if ends after X repetitions, set another rule
if ('times' === $this->convertString('repetition_end')) {
$rules['repetitions'] = 'required|numeric|between:0,254';
$rules['repetitions'] = 'required|numeric|min:0|max:255';
}
// if foreign amount, currency must be different.
if (null !== $this->convertFloat('foreign_amount')) { // intentional float, used because it defaults to null.
@@ -210,10 +211,10 @@ class RecurrenceFormRequest extends FormRequest
$type = strtolower($this->convertString('transaction_type'));
if (strtolower(TransactionType::WITHDRAWAL) === $type) {
$rules['source_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['destination_name'] = 'between:1,255|nullable';
$rules['destination_name'] = 'min:1|max:255|nullable';
}
if (strtolower(TransactionType::DEPOSIT) === $type) {
$rules['source_name'] = 'between:1,255|nullable';
$rules['source_name'] = 'min:1|max:255|nullable';
$rules['destination_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
}
if (strtolower(TransactionType::TRANSFER) === $type) {
@@ -227,7 +228,7 @@ class RecurrenceFormRequest extends FormRequest
$recurrence = $this->route()->parameter('recurrence');
if ($recurrence instanceof Recurrence) {
$rules['id'] = 'required|numeric|exists:recurrences,id';
$rules['title'] = 'required|between:1,255|uniqueObjectForUser:recurrences,title,'.$recurrence->id;
$rules['title'] = 'required|min:1|max:255|uniqueObjectForUser:recurrences,title,'.$recurrence->id;
$rules['first_date'] = 'required|date';
}
@@ -279,12 +280,12 @@ class RecurrenceFormRequest extends FormRequest
if ('deposit' === $type) {
$throwError = false;
$sourceId = (int) $data['deposit_source_id'];
$destinationId = (int) $data['destination_id'];
$destinationId = (int) ($data['destination_id'] ?? 0);
}
if ('transfer' === $type) {
$throwError = false;
$sourceId = (int) $data['source_id'];
$destinationId = (int) $data['destination_id'];
$destinationId = (int) ($data['destination_id'] ?? 0);
}
if (true === $throwError) {
throw new FireflyException(sprintf('Cannot handle transaction type "%s"', $this->convertString('transaction_type')));

View File

@@ -97,8 +97,8 @@ class RuleFormRequest extends FormRequest
// initial set of rules:
$rules = [
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
'description' => 'between:1,5000|nullable',
'title' => 'required|min:1|max:255|uniqueObjectForUser:rules,title',
'description' => 'min:1|max:32768|nullable',
'stop_processing' => 'boolean',
'rule_group_id' => 'required|belongsToUser:rule_groups',
'trigger' => 'required|in:store-journal,update-journal',
@@ -113,7 +113,7 @@ class RuleFormRequest extends FormRequest
$rule = $this->route()->parameter('rule');
if (null !== $rule) {
$rules['title'] = 'required|between:1,100|uniqueObjectForUser:rules,title,'.$rule->id;
$rules['title'] = 'required|min:1|max:255|uniqueObjectForUser:rules,title,'.$rule->id;
}
return $rules;

View File

@@ -59,18 +59,18 @@ class RuleGroupFormRequest extends FormRequest
*/
public function rules(): array
{
$titleRule = 'required|between:1,100|uniqueObjectForUser:rule_groups,title';
$titleRule = 'required|min:1|max:255|uniqueObjectForUser:rule_groups,title';
/** @var null|RuleGroup $ruleGroup */
$ruleGroup = $this->route()->parameter('ruleGroup');
if (null !== $ruleGroup) {
$titleRule = 'required|between:1,100|uniqueObjectForUser:rule_groups,title,'.$ruleGroup->id;
$titleRule = 'required|min:1|max:255|uniqueObjectForUser:rule_groups,title,'.$ruleGroup->id;
}
return [
'title' => $titleRule,
'description' => 'between:1,5000|nullable',
'description' => 'min:1|max:32768|nullable',
'active' => [new IsBoolean()],
];
}

View File

@@ -58,9 +58,9 @@ class UserFormRequest extends FormRequest
'id' => 'required|exists:users,id',
'email' => 'email|required',
'password' => 'confirmed|secure_password',
'blocked_code' => 'between:0,30|nullable',
'blocked' => 'between:0,1|numeric',
'is_owner' => 'between:0,1|numeric',
'blocked_code' => 'min:0|max:32|nullable',
'blocked' => 'min:0|max:1|numeric',
'is_owner' => 'min:0|max:1|numeric',
];
}
}

View File

@@ -93,12 +93,14 @@ class Location extends Model
return $rules;
}
/**
* Get all the accounts.
*/
public function accounts(): MorphMany
{
return $this->morphMany(Account::class, 'noteable');
return $this->morphMany(Account::class, 'locatable');
}
public function transactionJournals(): MorphMany
{
return $this->morphMany(TransactionJournal::class, 'locatable');
}
/**

View File

@@ -389,7 +389,7 @@ class AccountRepository implements AccountRepositoryInterface
if (!in_array($type, $list, true)) {
return null;
}
$currencyId = (int)$this->getMetaValue($account, 'currency_id');
$currencyId = (int) $this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) {
return TransactionCurrency::find($currencyId);
}
@@ -411,7 +411,7 @@ class AccountRepository implements AccountRepositoryInterface
return null;
}
if (1 === $result->count()) {
return (string)$result->first()->data;
return (string) $result->first()->data;
}
return null;
@@ -432,8 +432,8 @@ class AccountRepository implements AccountRepositoryInterface
$info = $account->transactions()->get(['transaction_currency_id', 'foreign_currency_id'])->toArray();
$currencyIds = [];
foreach ($info as $entry) {
$currencyIds[] = (int)$entry['transaction_currency_id'];
$currencyIds[] = (int)$entry['foreign_currency_id'];
$currencyIds[] = (int) $entry['transaction_currency_id'];
$currencyIds[] = (int) $entry['foreign_currency_id'];
}
$currencyIds = array_unique($currencyIds);
@@ -456,14 +456,14 @@ class AccountRepository implements AccountRepositoryInterface
AccountType::MORTGAGE => [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE],
];
if (array_key_exists(ucfirst($type), $sets)) {
$order = (int)$this->getAccountsByType($sets[ucfirst($type)])->max('order');
$order = (int) $this->getAccountsByType($sets[ucfirst($type)])->max('order');
app('log')->debug(sprintf('Return max order of "%s" set: %d', $type, $order));
return $order;
}
$specials = [AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION];
$order = (int)$this->getAccountsByType($specials)->max('order');
$order = (int) $this->getAccountsByType($specials)->max('order');
app('log')->debug(sprintf('Return max order of "%s" set (specials!): %d', $type, $order));
return $order;
@@ -544,7 +544,7 @@ class AccountRepository implements AccountRepositoryInterface
continue;
}
if ($index !== (int)$account->order) {
if ($index !== (int) $account->order) {
app('log')->debug(sprintf('Account #%d ("%s"): order should %d be but is %d.', $account->id, $account->name, $index, $account->order));
$account->order = $index;
$account->save();

View File

@@ -42,6 +42,7 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class BillRepository.
@@ -105,6 +106,7 @@ class BillRepository implements BillRepositoryInterface
public function destroyAll(): void
{
Log::channel('audit')->info('Delete all bills through destroyAll');
$this->user->bills()->delete();
}

View File

@@ -30,6 +30,7 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class AvailableBudgetRepository
@@ -79,6 +80,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
*/
public function destroyAll(): void
{
Log::channel('audit')->info('Delete all available budgets through destroyAll');
$this->user->availableBudgets()->delete();
}

View File

@@ -33,6 +33,7 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class BudgetLimitRepository
@@ -108,6 +109,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
/** @var Budget $budget */
foreach ($budgets as $budget) {
Log::channel('audit')->info(sprintf('Delete all budget limits of budget #%d ("%s") through destroyAll', $budget->id, $budget->name));
$budget->budgetlimits()->delete();
}
}

View File

@@ -45,6 +45,7 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class BudgetRepository.
@@ -329,6 +330,7 @@ class BudgetRepository implements BudgetRepositoryInterface
RuleAction::where('action_type', 'set_budget')->where('action_value', (string) $budget->id)->delete();
$budget->delete();
}
Log::channel('audit')->info('Delete all budgets through destroyAll');
}
public function getBudgets(): Collection

View File

@@ -36,6 +36,7 @@ use FireflyIII\Services\Internal\Update\CategoryUpdateService;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class CategoryRepository.
@@ -88,6 +89,7 @@ class CategoryRepository implements CategoryRepositoryInterface
RuleAction::where('action_type', 'set_category')->where('action_value', $category->name)->delete();
$category->delete();
}
Log::channel('audit')->info('Delete all categories through destroyAll');
}
/**

View File

@@ -36,6 +36,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class PiggyBankRepository.
@@ -48,6 +49,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
public function destroyAll(): void
{
Log::channel('audit')->info('Delete all piggy banks through destroyAll');
$this->user->piggyBanks()->delete();
}

View File

@@ -47,6 +47,7 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class RecurringRepository
@@ -116,6 +117,7 @@ class RecurringRepository implements RecurringRepositoryInterface
public function destroyAll(): void
{
Log::channel('audit')->info('Delete all recurring transactions through destroyAll');
$this->user->recurrences()->delete();
}

View File

@@ -31,6 +31,7 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class RuleGroupRepository.
@@ -152,6 +153,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
public function destroyAll(): void
{
Log::channel('audit')->info('Delete all rule groups through destroyAll');
$groups = $this->get();
/** @var RuleGroup $group */

View File

@@ -34,6 +34,7 @@ use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class TagRepository.
@@ -64,6 +65,7 @@ class TagRepository implements TagRepositoryInterface
*/
public function destroyAll(): void
{
Log::channel('audit')->info('Delete all tags through destroyAll');
$tags = $this->get();
/** @var Tag $tag */

View File

@@ -273,10 +273,6 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return TransactionCurrency::where('code', $currencyCode)->first();
}
/**
* @param TransactionCurrency $currency
* Enables a currency
*/
public function enable(TransactionCurrency $currency): void
{
$this->userGroup->currencies()->syncWithoutDetaching([$currency->id]);

View File

@@ -22,7 +22,9 @@ class IsValidAmount implements ValidationRule
// must not be empty:
if($this->emptyString($value)) {
$fail('validation.filled')->translate();
Log::info(sprintf('IsValidAmount: "%s" cannot be empty.', $value));
$message = sprintf('IsValidAmount: "%s" cannot be empty.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
@@ -30,7 +32,9 @@ class IsValidAmount implements ValidationRule
// must be a number:
if(!$this->isValidNumber($value)) {
$fail('validation.numeric')->translate();
Log::info(sprintf('IsValidAmount: "%s" is not a number.', $value));
$message = sprintf('IsValidAmount: "%s" is not a number.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
@@ -38,25 +42,31 @@ class IsValidAmount implements ValidationRule
// must not be scientific notation:
if($this->scientificNumber($value)) {
$fail('validation.scientific_notation')->translate();
Log::info(sprintf('IsValidAmount: "%s" cannot be in the scientific notation.', $value));
$message = sprintf('IsValidAmount: "%s" cannot be in the scientific notation.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be more than minus a lots:
if($this->lessThanLots($value)) {
$amount = bcmul('-1', self::BIG_AMOUNT);
$amount = bcmul('-1', self::BIG_AMOUNT);
$fail('validation.gte.numeric')->translate(['value' => $amount]);
Log::info(sprintf('IsValidAmount: "%s" must be more than %s.', $value, $amount));
$message = sprintf('IsValidAmount: "%s" must be more than %s.', $value, $amount);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be less than 100 million and 1709:
if($this->moreThanLots($value)) {
Log::info(sprintf('IsValidPositiveAmount: "%s" must be more than %s.', $value, self::BIG_AMOUNT));
$fail('validation.lte.numeric')->translate(['value' => self::BIG_AMOUNT]);
$message = sprintf('IsValidAmount: "%s" must be more than %s.', $value, self::BIG_AMOUNT);
Log::debug($message);
Log::channel('audit')->info($message);
}
Log::info(sprintf('IsValidAmount: "%s" is a valid positive amount.', $value));
Log::debug(sprintf('IsValidAmount: "%s" is a valid positive amount.', $value));
}
}

View File

@@ -21,7 +21,9 @@ class IsValidPositiveAmount implements ValidationRule
// must not be empty:
if($this->emptyString($value)) {
$fail('validation.filled')->translate();
Log::info(sprintf('IsValidPositiveAmount: "%s" cannot be empty.', $value));
$message = sprintf('IsValidPositiveAmount: "%s" cannot be empty.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
@@ -29,29 +31,37 @@ class IsValidPositiveAmount implements ValidationRule
// must be a number:
if(!$this->isValidNumber($value)) {
$fail('validation.numeric')->translate();
Log::info(sprintf('IsValidPositiveAmount: "%s" is not a number.', $value));
$message = sprintf('IsValidPositiveAmount: "%s" is not a number.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must not be scientific notation:
if($this->scientificNumber($value)) {
$fail('validation.scientific_notation')->translate();
Log::info(sprintf('IsValidPositiveAmount: "%s" cannot be in the scientific notation.', $value));
$message = sprintf('IsValidPositiveAmount: "%s" cannot be in the scientific notation.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be more than zero:
if($this->lessOrEqualToZero($value)) {
$fail('validation.more_than_zero')->translate();
Log::info(sprintf('IsValidPositiveAmount: "%s" must be more than zero.', $value));
$message = sprintf('IsValidPositiveAmount: "%s" must be more than zero.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be less than 100 million and 1709:
if($this->moreThanLots($value)) {
Log::info(sprintf('IsValidPositiveAmount: "%s" must be less than %s.', $value, self::BIG_AMOUNT));
$fail('validation.lte.numeric')->translate(['value' => self::BIG_AMOUNT]);
$message = sprintf('IsValidPositiveAmount: "%s" must be less than %s.', $value, self::BIG_AMOUNT);
Log::debug($message);
Log::channel('audit')->info($message);
}
Log::info(sprintf('IsValidPositiveAmount: "%s" is a valid positive amount.', $value));
Log::debug(sprintf('IsValidPositiveAmount: "%s" is a valid positive amount.', $value));
}
}

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Rules;
use FireflyIII\Support\Validation\ValidatesAmountsTrait;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Facades\Log;
class IsValidZeroOrMoreAmount implements ValidationRule
{
use ValidatesAmountsTrait;
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function validate(string $attribute, mixed $value, \Closure $fail): void
{
$value = (string)$value;
// must not be empty:
if($this->emptyString($value)) {
$fail('validation.filled')->translate();
$message = sprintf('IsValidZeroOrMoreAmount: "%s" cannot be empty.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be a number:
if(!$this->isValidNumber($value)) {
$fail('validation.numeric')->translate();
$message = sprintf('IsValidZeroOrMoreAmount: "%s" is not a number.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must not be scientific notation:
if($this->scientificNumber($value)) {
$fail('validation.scientific_notation')->translate();
$message = sprintf('IsValidZeroOrMoreAmount: "%s" cannot be in the scientific notation.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be zero or more
if(!$this->zeroOrMore($value)) {
$fail('validation.more_than_zero_correct')->translate();
$message = sprintf('IsValidZeroOrMoreAmount: "%s" must be zero or more.', $value);
Log::debug($message);
Log::channel('audit')->info($message);
return;
}
// must be less than 100 million and 1709:
if($this->moreThanLots($value)) {
$fail('validation.lte.numeric')->translate(['value' => self::BIG_AMOUNT]);
$message = sprintf('IsValidPositiveAmount: "%s" must be less than %s.', $value, self::BIG_AMOUNT);
Log::debug($message);
Log::channel('audit')->info($message);
}
Log::debug(sprintf('IsValidZeroOrMoreAmount: "%s" is a valid positive amount.', $value));
}
}

View File

@@ -41,7 +41,9 @@ class UniqueAccountNumber implements ValidationRule
*/
public function __construct(?Account $account, ?string $expectedType)
{
app('log')->debug('Constructed UniqueAccountNumber');
app('log')
->debug('Constructed UniqueAccountNumber')
;
$this->account = $account;
$this->expectedType = $expectedType;
// a very basic fix to make sure we get the correct account type:
@@ -62,7 +64,7 @@ class UniqueAccountNumber implements ValidationRule
*/
public function message(): string
{
return (string)trans('validation.unique_account_number_for_user');
return (string) trans('validation.unique_account_number_for_user');
}
/**

View File

@@ -40,13 +40,13 @@ class UserGroupAccount implements BinderInterface
{
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$currency = Account::where('id', (int)$value)
$user = auth()->user();
$account = Account::where('id', (int)$value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $currency) {
return $currency;
if (null !== $account) {
return $account;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* UserGroupTransaction.php
* Copyright (c) 2024 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Binder;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\User;
use Illuminate\Routing\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class UserGroupTransaction.
*/
class UserGroupTransaction implements BinderInterface
{
public static function routeBinder(string $value, Route $route): TransactionGroup
{
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$group = TransactionGroup::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $group) {
return $group;
}
}
throw new NotFoundHttpException();
}
}

View File

@@ -216,10 +216,9 @@ class Preferences
}
/**
* @param null $default
* TODO remove me.
*
* @return null|preference
* TODO remove me
* @param null $default
*
* @throws FireflyException
*/

View File

@@ -65,6 +65,23 @@ trait AppendsLocationData
*/
abstract public function boolean($key = null, $default = false);
public function addFromromTransactionStore(array $information, array $return): array
{
$return['store_location'] = false;
if (true === $information['store_location']) {
$long = array_key_exists('longitude', $information) ? $information['longitude'] : null;
$lat = array_key_exists('latitude', $information) ? $information['latitude'] : null;
if (null !== $long && null !== $lat && $this->validLongitude($long) && $this->validLatitude($lat)) {
$return['store_location'] = true;
$return['longitude'] = $information['longitude'];
$return['latitude'] = $information['latitude'];
$return['zoom_level'] = $information['zoom_level'];
}
}
return $return;
}
/**
* Read the submitted Request data and add new or updated Location data to the array.
*/
@@ -119,6 +136,20 @@ trait AppendsLocationData
return $data;
}
private function validLongitude(string $longitude): bool
{
$number = (float) $longitude;
return $number >= -180 && $number <= 180;
}
private function validLatitude(string $latitude): bool
{
$number = (float) $latitude;
return $number >= -90 && $number <= 90;
}
private function getLocationKey(?string $prefix, string $key): string
{
if (null === $prefix) {

View File

@@ -81,8 +81,7 @@ class AmountFormat extends AbstractExtension
/**
* Will format the amount by the currency related to the given account.
*
* @return twigFunction
* TODO remove me when layout v1 is deprecated
* TODO Remove me when v2 hits.
*/
protected function formatAmountByAccount(): TwigFunction
{

View File

@@ -346,8 +346,7 @@ class General extends AbstractExtension
}
/**
* @return twigFunction
* TODO remove me when layout v1 is deprecated
* TODO Remove me when v2 hits.
*/
protected function getMetaField(): TwigFunction
{

View File

@@ -47,6 +47,11 @@ trait ValidatesAmountsTrait
return -1 === bccomp($value, '0') || 0 === bccomp($value, '0');
}
final protected function zeroOrMore(string $value): bool
{
return 1 === bccomp($value, '0') || 0 === bccomp($value, '0');
}
final protected function moreThanLots(string $value): bool
{
return 1 === bccomp($value, self::BIG_AMOUNT) || 0 === bccomp($value, self::BIG_AMOUNT);

View File

@@ -199,8 +199,6 @@ class AccountTransformer extends AbstractTransformer
}
/**
* @return array
*
* TODO refactor call to get~OpeningBalanceAmount / Date because it is a lot of queries
*/
private function getOpeningBalance(Account $account, string $accountType): array

View File

@@ -26,8 +26,13 @@ namespace FireflyIII\Transformers\V2;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Location;
use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Models\TransactionType;
@@ -35,99 +40,232 @@ use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\NullArrayObject;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* Class TransactionGroupTransformer
*/
class TransactionGroupTransformer extends AbstractTransformer
{
private ExchangeRateConverter $converter;
private array $currencies = [];
private array $accountTypes = []; // account types collection.
private array $journals = []; // collection of all journals and some important meta-data.
private array $objects = [];
private array $currencies = []; // collection of all currencies for this transformer.
private TransactionCurrency $default;
private array $meta;
private array $notes;
private array $tags;
private ExchangeRateConverter $converter;
// private array $currencies = [];
// private array $transactionTypes = [];
// private array $meta = [];
// private array $notes = [];
// private array $locations = [];
// private array $tags = [];
// private array $amounts = [];
// private array $foreignAmounts = [];
// private array $journalCurrencies = [];
// private array $foreignCurrencies = [];
public function collectMetaData(Collection $objects): void
{
// start with currencies:
$currencies = [];
$journals = [];
$collectForObjects = false;
/** @var array $object */
/** @var array|TransactionGroup $object */
foreach ($objects as $object) {
foreach ($object['sums'] as $sum) {
$id = (int) $sum['currency_id'];
$currencies[$id] ??= TransactionCurrency::find($sum['currency_id']);
if (is_array($object)) {
$this->collectForArray($object);
}
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
$id = (int) $transaction['transaction_journal_id'];
$journals[$id] = [];
if ($object instanceof TransactionGroup) {
$this->collectForObject($object);
$collectForObjects = true;
}
}
$this->currencies = $currencies;
$this->default = app('amount')->getDefaultCurrency();
// grab meta for all journals:
$meta = TransactionJournalMeta::whereIn('transaction_journal_id', array_keys($journals))->get();
$this->default = app('amount')->getDefaultCurrency();
$this->converter = new ExchangeRateConverter();
/** @var TransactionJournalMeta $entry */
foreach ($meta as $entry) {
$id = $entry->transaction_journal_id;
$this->meta[$id][$entry->name] = $entry->data;
$this->collectAllMetaData();
$this->collectAllNotes();
$this->collectAllLocations();
$this->collectAllTags();
if ($collectForObjects) {
$this->collectAllCurrencies();
// $this->collectAllAmounts();
// $this->collectTransactionTypes();
// $this->collectAccounts();
// source accounts
// destination accounts
}
// grab all notes for all journals:
$notes = Note::whereNoteableType(TransactionJournal::class)->whereIn('noteable_id', array_keys($journals))->get();
/** @var Note $note */
foreach ($notes as $note) {
$id = $note->noteable_id;
$this->notes[$id] = $note;
}
// grab all tags for all journals:
$tags = DB::table('tag_transaction_journal')
->leftJoin('tags', 'tags.id', 'tag_transaction_journal.tag_id')
->whereIn('tag_transaction_journal.transaction_journal_id', array_keys($journals))
->get(['tag_transaction_journal.transaction_journal_id', 'tags.tag'])
;
/** @var \stdClass $tag */
foreach ($tags as $tag) {
$id = (int) $tag->transaction_journal_id;
$this->tags[$id][] = $tag->tag;
}
// create converter
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$this->converter = new ExchangeRateConverter();
}
public function transform(array $group): array
public function transform(array|TransactionGroup $group): array
{
$first = reset($group['transactions']);
if (is_array($group)) {
$first = reset($group['transactions']);
return [
'id' => (string) $group['id'],
'created_at' => $group['created_at']->toAtomString(),
'updated_at' => $group['updated_at']->toAtomString(),
'user' => (string) $first['user_id'],
'user_group' => (string) $first['user_group_id'],
'group_title' => $group['title'] ?? null,
'transactions' => $this->transformTransactions($group['transactions'] ?? []),
'links' => [
[
'rel' => 'self',
'uri' => sprintf('/transactions/%d', $group['id']),
],
],
];
}
return [
'id' => (string) $group['id'],
'created_at' => $first['created_at']->toAtomString(),
'updated_at' => $first['updated_at']->toAtomString(),
'user' => (string) $first['user_id'],
'user_group' => (string) $first['user_group_id'],
'group_title' => $group['title'] ?? null,
'transactions' => $this->transformTransactions($group['transactions'] ?? []),
'id' => (string) $group->id,
'created_at' => $group->created_at->toAtomString(),
'updated_at' => $group->created_at->toAtomString(),
'user' => (string) $group->user_id,
'user_group' => (string) $group->user_group_id,
'group_title' => $group->title ?? null,
'transactions' => $this->transformJournals($group),
'links' => [
[
'rel' => 'self',
'uri' => sprintf('/transactions/%d', $group['id']),
'uri' => sprintf('/transactions/%d', $group->id),
],
],
];
}
private function transformJournals(TransactionGroup $group): array
{
$return = [];
/** @var TransactionJournal $journal */
foreach ($group->transactionJournals as $journal) {
$return[] = $this->transformJournal($journal);
}
return $return;
}
/**
* @throws FireflyException
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
private function transformJournal(TransactionJournal $journal): array
{
$id = $journal->id;
/** @var null|TransactionCurrency $foreignCurrency */
$foreignCurrency = null;
/** @var TransactionCurrency $currency */
$currency = $this->currencies[$this->journals[$id]['currency_id']];
$nativeForeignAmount = null;
$amount = $this->journals[$journal->id]['amount'];
$foreignAmount = $this->journals[$journal->id]['foreign_amount'];
$meta = new NullArrayObject($this->meta[$id] ?? []);
// has foreign amount?
if (null !== $foreignAmount) {
$foreignCurrency = $this->currencies[$this->journals[$id]['foreign_currency_id']];
$nativeForeignAmount = $this->converter->convert($this->default, $foreignCurrency, $journal->date, $foreignAmount);
}
$nativeAmount = $this->converter->convert($this->default, $currency, $journal->date, $amount);
$longitude = null;
$latitude = null;
$zoomLevel = null;
if (array_key_exists('location', $this->journals[$id])) {
$latitude = (string) $this->journals[$id]['location']['latitude'];
$longitude = (string) $this->journals[$id]['location']['longitude'];
$zoomLevel = $this->journals[$id]['location']['zoom_level'];
}
return [
'user' => (string) $journal->user_id,
'user_group' => (string) $journal->user_group_id,
'transaction_journal_id' => (string) $journal->id,
'type' => $this->journals[$journal->id]['type'],
'date' => $journal->date->toAtomString(),
'order' => $journal->order,
'amount' => $amount,
'native_amount' => $nativeAmount,
'foreign_amount' => $foreignAmount,
'native_foreign_amount' => $nativeForeignAmount,
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
// converted to native currency
'native_currency_id' => (string) $this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_name' => $this->default->name,
'native_currency_symbol' => $this->default->symbol,
'native_currency_decimal_places' => $this->default->decimal_places,
// foreign currency amount:
'foreign_currency_id' => $foreignCurrency?->id,
'foreign_currency_code' => $foreignCurrency?->code,
'foreign_currency_name' => $foreignCurrency?->name,
'foreign_currency_symbol' => $foreignCurrency?->symbol,
'foreign_currency_decimal_places' => $foreignCurrency?->decimal_places,
'description' => $journal->description,
'source_id' => (string) $this->journals[$id]['source_account_id'],
'source_name' => $this->journals[$id]['source_account_name'],
'source_iban' => $this->journals[$id]['source_account_iban'],
'source_type' => $this->journals[$id]['source_account_type'],
'destination_id' => (string) $this->journals[$id]['destination_account_id'],
'destination_name' => $this->journals[$id]['destination_account_name'],
'destination_iban' => $this->journals[$id]['destination_account_iban'],
'destination_type' => $this->journals[$id]['destination_account_type'],
'budget_id' => $this->journals[$id]['budget_id'],
'budget_name' => $this->journals[$id]['budget_name'],
'category_id' => $this->journals[$id]['category_id'],
'category_name' => $this->journals[$id]['category_name'],
'bill_id' => $this->journals[$id]['bill_id'],
'bill_name' => $this->journals[$id]['bill_name'],
'reconciled' => $this->journals[$id]['reconciled'],
'notes' => $this->journals[$id]['notes'] ?? null,
'tags' => $this->journals[$id]['tags'] ?? [],
'internal_reference' => $meta['internal_reference'],
'external_id' => $meta['external_id'],
'original_source' => $meta['original_source'],
'recurrence_id' => $meta['recurrence_id'],
'recurrence_total' => $meta['recurrence_total'],
'recurrence_count' => $meta['recurrence_count'],
'external_url' => $meta['external_url'],
'import_hash_v2' => $meta['import_hash_v2'],
'sepa_cc' => $meta['sepa_cc'],
'sepa_ct_op' => $meta['sepa_ct_op'],
'sepa_ct_id' => $meta['sepa_ct_id'],
'sepa_db' => $meta['sepa_db'],
'sepa_country' => $meta['sepa_country'],
'sepa_ep' => $meta['sepa_ep'],
'sepa_ci' => $meta['sepa_ci'],
'sepa_batch_id' => $meta['sepa_batch_id'],
'interest_date' => $this->date($meta['interest_date']),
'book_date' => $this->date($meta['book_date']),
'process_date' => $this->date($meta['process_date']),
'due_date' => $this->date($meta['due_date']),
'payment_date' => $this->date($meta['payment_date']),
'invoice_date' => $this->date($meta['invoice_date']),
// location data
'longitude' => $longitude,
'latitude' => $latitude,
'zoom_level' => $zoomLevel,
//
// 'has_attachments' => $this->hasAttachments((int) $row['transaction_journal_id']),
];
}
private function transformTransactions(array $transactions): array
{
$return = [];
@@ -167,6 +305,15 @@ class TransactionGroupTransformer extends AbstractTransformer
}
$this->converter->summarize();
$longitude = null;
$latitude = null;
$zoomLevel = null;
if (array_key_exists('location', $this->journals[$journalId])) {
$latitude = (string) $this->journals[$journalId]['location']['latitude'];
$longitude = (string) $this->journals[$journalId]['location']['longitude'];
$zoomLevel = $this->journals[$journalId]['location']['zoom_level'];
}
return [
'user' => (string) $transaction['user_id'],
'user_group' => (string) $transaction['user_group_id'],
@@ -241,9 +388,9 @@ class TransactionGroupTransformer extends AbstractTransformer
'invoice_date' => $this->date($meta['invoice_date']),
// location data
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
'longitude' => $longitude,
'latitude' => $latitude,
'zoom_level' => $zoomLevel,
//
// 'has_attachments' => $this->hasAttachments((int) $row['transaction_journal_id']),
];
@@ -312,4 +459,162 @@ class TransactionGroupTransformer extends AbstractTransformer
return $res;
}
private function collectForArray(array $object): void
{
foreach ($object['sums'] as $sum) {
$this->currencies[(int) $sum['currency_id']] ??= TransactionCurrency::find($sum['currency_id']);
}
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
$this->journals[(int) $transaction['transaction_journal_id']] = [];
}
}
private function collectAllMetaData(): void
{
$meta = TransactionJournalMeta::whereIn('transaction_journal_id', array_keys($this->journals))->get();
/** @var TransactionJournalMeta $entry */
foreach ($meta as $entry) {
$id = $entry->transaction_journal_id;
$this->journals[$id]['meta'] ??= [];
$this->journals[$id]['meta'][$entry->name] = $entry->data;
}
}
private function collectAllNotes(): void
{
// grab all notes for all journals:
$notes = Note::whereNoteableType(TransactionJournal::class)->whereIn('noteable_id', array_keys($this->journals))->get();
/** @var Note $note */
foreach ($notes as $note) {
$id = $note->noteable_id;
$this->journals[$id]['notes'] = $note->text;
}
}
private function collectAllLocations(): void
{
// grab all locations for all journals:
$locations = Location::whereLocatableType(TransactionJournal::class)->whereIn('locatable_id', array_keys($this->journals))->get();
/** @var Location $location */
foreach ($locations as $location) {
$id = $location->locatable_id;
$this->journals[$id]['location'] = [
'latitude' => $location->latitude,
'longitude' => $location->longitude,
'zoom_level' => $location->zoom_level,
];
}
}
private function collectAllTags(): void
{
// grab all tags for all journals:
$tags = DB::table('tag_transaction_journal')
->leftJoin('tags', 'tags.id', 'tag_transaction_journal.tag_id')
->whereIn('tag_transaction_journal.transaction_journal_id', array_keys($this->journals))
->get(['tag_transaction_journal.transaction_journal_id', 'tags.tag'])
;
/** @var \stdClass $tag */
foreach ($tags as $tag) {
$id = (int) $tag->transaction_journal_id;
$this->journals[$id]['tags'][] = $tag->tag;
}
}
private function collectForObject(TransactionGroup $object): void
{
foreach ($object->transactionJournals as $journal) {
$this->journals[$journal->id] = [];
$this->objects[] = $journal;
}
}
private function collectAllCurrencies(): void
{
/** @var TransactionJournal $journal */
foreach ($this->objects as $journal) {
$id = $journal->id;
$this->journals[$id]['reconciled'] = false;
$this->journals[$id]['foreign_amount'] = null;
$this->journals[$id]['foreign_currency_id'] = null;
$this->journals[$id]['amount'] = null;
$this->journals[$id]['currency_id'] = null;
$this->journals[$id]['type'] = $journal->transactionType->type;
$this->journals[$id]['budget_id'] = null;
$this->journals[$id]['budget_name'] = null;
$this->journals[$id]['category_id'] = null;
$this->journals[$id]['category_name'] = null;
$this->journals[$id]['bill_id'] = null;
$this->journals[$id]['bill_name'] = null;
// collect budget:
/** @var null|Budget $budget */
$budget = $journal->budgets()->first();
if (null !== $budget) {
$this->journals[$id]['budget_id'] = (string) $budget->id;
$this->journals[$id]['budget_name'] = $budget->name;
}
// collect category:
/** @var null|Category $category */
$category = $journal->categories()->first();
if (null !== $category) {
$this->journals[$id]['category_id'] = (string) $category->id;
$this->journals[$id]['category_name'] = $category->name;
}
// collect bill:
if (null !== $journal->bill_id) {
$bill = $journal->bill;
$this->journals[$id]['bill_id'] = (string) $bill->id;
$this->journals[$id]['bill_name'] = $bill->name;
}
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
if (-1 === bccomp($transaction->amount, '0')) {
// only collect source account info
$account = $transaction->account;
$this->accountTypes[$account->account_type_id] ??= $account->accountType->type;
$this->journals[$id]['source_account_name'] = $account->name;
$this->journals[$id]['source_account_iban'] = $account->iban;
$this->journals[$id]['source_account_type'] = $this->accountTypes[$account->account_type_id];
$this->journals[$id]['source_account_id'] = $transaction->account_id;
$this->journals[$id]['reconciled'] = $transaction->reconciled;
continue;
}
// add account
$account = $transaction->account;
$this->accountTypes[$account->account_type_id] ??= $account->accountType->type;
$this->journals[$id]['destination_account_name'] = $account->name;
$this->journals[$id]['destination_account_iban'] = $account->iban;
$this->journals[$id]['destination_account_type'] = $this->accountTypes[$account->account_type_id];
$this->journals[$id]['destination_account_id'] = $transaction->account_id;
// find and set currency
$currencyId = $transaction->transaction_currency_id;
$this->currencies[$currencyId] ??= $transaction->transactionCurrency;
$this->journals[$id]['currency_id'] = $currencyId;
$this->journals[$id]['amount'] = $transaction->amount;
// find and set foreign currency
if (null !== $transaction->foreign_currency_id) {
$foreignCurrencyId = $transaction->foreign_currency_id;
$this->currencies[$foreignCurrencyId] ??= $transaction->foreignCurrency;
$this->journals[$id]['foreign_currency_id'] = $foreignCurrencyId;
$this->journals[$id]['foreign_amount'] = $transaction->foreign_amount;
}
// find and set destination account info.
}
}
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Validation;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
@@ -50,30 +51,42 @@ trait CurrencyValidation
if (!is_array($transaction)) {
continue;
}
// if foreign amount is present, then the currency must be as well.
if (array_key_exists('foreign_amount', $transaction)
&& !(array_key_exists('foreign_currency_id', $transaction)
|| array_key_exists(
'foreign_currency_code',
$transaction
))
&& 0 !== bccomp('0', $transaction['foreign_amount'])
) {
$validator->errors()->add(
'transactions.'.$index.'.foreign_amount',
(string)trans('validation.require_currency_info')
);
if (!array_key_exists('foreign_amount', $transaction) && !array_key_exists('foreign_currency_id', $transaction) && !array_key_exists('foreign_currency_code', $transaction)) {
Log::debug('validateForeignCurrencyInformation: no foreign currency information present at all.');
continue;
}
// if the currency is present, then the amount must be present as well.
if ((array_key_exists('foreign_currency_id', $transaction) || array_key_exists('foreign_currency_code', $transaction))
&& !array_key_exists(
'foreign_amount',
$transaction
)) {
$validator->errors()->add(
'transactions.'.$index.'.foreign_amount',
(string)trans('validation.require_currency_amount')
);
$foreignAmount = (string) ($transaction['foreign_amount'] ?? '');
$foreignId = $transaction['foreign_currency_id'] ?? null;
$foreignCode = $transaction['foreign_currency_code'] ?? null;
if ('' === $foreignAmount) {
Log::debug('validateForeignCurrencyInformation: foreign amount is "".');
if (
(array_key_exists('foreign_currency_id', $transaction) || array_key_exists('foreign_currency_code', $transaction))
&& (null !== $foreignId || null !== $foreignCode)
) {
$validator->errors()->add('transactions.'.$index.'.foreign_amount', (string) trans('validation.require_currency_amount'));
$validator->errors()->add('transactions.'.$index.'.foreign_currency_id', (string) trans('validation.require_currency_amount'));
$validator->errors()->add('transactions.'.$index.'.foreign_currency_code', (string) trans('validation.require_currency_amount'));
}
continue;
}
$compare = bccomp('0', $foreignAmount);
if (-1 === $compare) {
Log::debug('validateForeignCurrencyInformation: array contains foreign amount info.');
if (!array_key_exists('foreign_currency_id', $transaction) && !array_key_exists('foreign_currency_code', $transaction)) {
Log::debug('validateForeignCurrencyInformation: array contains NO foreign currency info.');
$validator->errors()->add('transactions.'.$index.'.foreign_amount', (string) trans('validation.require_currency_info'));
}
}
if (0 === $compare && ('' !== (string) $foreignId || '' !== (string) $foreignCode)) {
Log::debug('validateForeignCurrencyInformation: array contains foreign currency info, but zero amount.');
$validator->errors()->add('transactions.'.$index.'.foreign_currency_id', (string) trans('validation.require_currency_amount'));
$validator->errors()->add('transactions.'.$index.'.foreign_currency_code', (string) trans('validation.require_currency_amount'));
$validator->errors()->add('transactions.'.$index.'.foreign_amount', (string) trans('validation.require_currency_amount'));
}
}
}

View File

@@ -3,6 +3,41 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.1.6 - 2024-01-07
### Fixed
- Type validation error
## 6.1.5 - 2024-01-07
### Added
- More audit logs
- Sanity check in date ranges
- More uniform length and size validations
### Changed
- Slightly changed text, thanks @maureenferreira!
### Fixed
- [Issue 8328](https://github.com/firefly-iii/firefly-iii/issues/8328) Some extra fixes for non-zero foreign amounts
- Updated links in `.env.example`, thanks @lemuelroberto!
## 6.1.4 - 2024-01-03
### Fixed
- [Issue 8328](https://github.com/firefly-iii/firefly-iii/issues/8328) Asking for non-zero foreign amount despite not being used
## 6.1.3 - 2024-01-03
### Fixed
- [Issue 8326](https://github.com/firefly-iii/firefly-iii/issues/8326) Asking for non-zero foreign amount despite not being used
## 6.1.2 - 2024-01-03
### Changed

102
composer.lock generated
View File

@@ -5721,16 +5721,16 @@
},
{
"name": "spatie/ignition",
"version": "1.11.3",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/ignition.git",
"reference": "3d886de644ff7a5b42e4d27c1e1f67c8b5f00044"
"reference": "5b6f801c605a593106b623e45ca41496a6e7d56d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/ignition/zipball/3d886de644ff7a5b42e4d27c1e1f67c8b5f00044",
"reference": "3d886de644ff7a5b42e4d27c1e1f67c8b5f00044",
"url": "https://api.github.com/repos/spatie/ignition/zipball/5b6f801c605a593106b623e45ca41496a6e7d56d",
"reference": "5b6f801c605a593106b623e45ca41496a6e7d56d",
"shasum": ""
},
"require": {
@@ -5800,20 +5800,20 @@
"type": "github"
}
],
"time": "2023-10-18T14:09:40+00:00"
"time": "2024-01-03T15:49:39+00:00"
},
{
"name": "spatie/laravel-html",
"version": "3.3.0",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-html.git",
"reference": "00faf80c459ca2a4cd9c6fe9c0e1a16b89216c2e"
"reference": "20bd3185ae085b2eced952bc5191cb8eb922250e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/00faf80c459ca2a4cd9c6fe9c0e1a16b89216c2e",
"reference": "00faf80c459ca2a4cd9c6fe9c0e1a16b89216c2e",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/20bd3185ae085b2eced952bc5191cb8eb922250e",
"reference": "20bd3185ae085b2eced952bc5191cb8eb922250e",
"shasum": ""
},
"require": {
@@ -5870,7 +5870,7 @@
"spatie"
],
"support": {
"source": "https://github.com/spatie/laravel-html/tree/3.3.0"
"source": "https://github.com/spatie/laravel-html/tree/3.4.0"
},
"funding": [
{
@@ -5878,39 +5878,39 @@
"type": "custom"
}
],
"time": "2023-10-24T06:34:29+00:00"
"time": "2024-01-05T16:35:10+00:00"
},
{
"name": "spatie/laravel-ignition",
"version": "2.3.3",
"version": "2.4.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-ignition.git",
"reference": "66499cd3c858642ded56dafb8fa0352057ca20dd"
"reference": "b9395ba48d3f30d42092cf6ceff75ed7256cd604"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/66499cd3c858642ded56dafb8fa0352057ca20dd",
"reference": "66499cd3c858642ded56dafb8fa0352057ca20dd",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/b9395ba48d3f30d42092cf6ceff75ed7256cd604",
"reference": "b9395ba48d3f30d42092cf6ceff75ed7256cd604",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"illuminate/support": "^10.0",
"illuminate/support": "^10.0|^11.0",
"php": "^8.1",
"spatie/flare-client-php": "^1.3.5",
"spatie/ignition": "^1.9",
"symfony/console": "^6.2.3",
"symfony/var-dumper": "^6.2.3"
"symfony/console": "^6.2.3|^7.0",
"symfony/var-dumper": "^6.2.3|^7.0"
},
"require-dev": {
"livewire/livewire": "^2.11",
"livewire/livewire": "^2.11|^3.3.5",
"mockery/mockery": "^1.5.1",
"openai-php/client": "^0.3.4",
"orchestra/testbench": "^8.0",
"pestphp/pest": "^1.22.3",
"openai-php/client": "^0.8.1",
"orchestra/testbench": "^8.0|^9.0",
"pestphp/pest": "^2.30",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan-deprecation-rules": "^1.1.1",
"phpstan/phpstan-phpunit": "^1.3.3",
@@ -5970,7 +5970,7 @@
"type": "github"
}
],
"time": "2023-12-21T09:43:05+00:00"
"time": "2024-01-04T14:51:24+00:00"
},
{
"name": "spatie/period",
@@ -9494,36 +9494,36 @@
},
{
"name": "larastan/larastan",
"version": "v2.7.0",
"version": "v2.8.0",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "a2610d46b9999cf558d9900ccb641962d1442f55"
"reference": "d60c1a6d49fcbb54b78922a955a55820abdbe3c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/a2610d46b9999cf558d9900ccb641962d1442f55",
"reference": "a2610d46b9999cf558d9900ccb641962d1442f55",
"url": "https://api.github.com/repos/larastan/larastan/zipball/d60c1a6d49fcbb54b78922a955a55820abdbe3c7",
"reference": "d60c1a6d49fcbb54b78922a955a55820abdbe3c7",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^9.52.16 || ^10.28.0",
"illuminate/container": "^9.52.16 || ^10.28.0",
"illuminate/contracts": "^9.52.16 || ^10.28.0",
"illuminate/database": "^9.52.16 || ^10.28.0",
"illuminate/http": "^9.52.16 || ^10.28.0",
"illuminate/pipeline": "^9.52.16 || ^10.28.0",
"illuminate/support": "^9.52.16 || ^10.28.0",
"illuminate/console": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/container": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/contracts": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/database": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/http": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0",
"php": "^8.0.2",
"phpmyadmin/sql-parser": "^5.8.2",
"phpstan/phpstan": "^1.10.41"
"phpstan/phpstan": "^1.10.50"
},
"require-dev": {
"nikic/php-parser": "^4.17.1",
"orchestra/canvas": "^7.11.1 || ^8.11.0",
"orchestra/testbench": "^7.33.0 || ^8.13.0",
"phpunit/phpunit": "^9.6.13"
"orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0",
"orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0",
"phpunit/phpunit": "^9.6.13 || ^10.5"
},
"suggest": {
"orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
@@ -9571,7 +9571,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v2.7.0"
"source": "https://github.com/larastan/larastan/tree/v2.8.0"
},
"funding": [
{
@@ -9591,7 +9591,7 @@
"type": "patreon"
}
],
"time": "2023-12-04T19:21:38+00:00"
"time": "2024-01-02T22:09:07+00:00"
},
{
"name": "mockery/mockery",
@@ -10146,16 +10146,16 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.24.5",
"version": "1.25.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc"
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fedf211ff14ec8381c9bf5714e33a7a552dd1acc",
"reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240",
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240",
"shasum": ""
},
"require": {
@@ -10187,22 +10187,22 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.5"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0"
},
"time": "2023-12-16T09:33:33+00:00"
"time": "2024-01-04T17:06:16+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.10.50",
"version": "1.10.54",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4"
"reference": "3e25f279dada0adc14ffd7bad09af2e2fc3523bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4",
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3e25f279dada0adc14ffd7bad09af2e2fc3523bb",
"reference": "3e25f279dada0adc14ffd7bad09af2e2fc3523bb",
"shasum": ""
},
"require": {
@@ -10251,7 +10251,7 @@
"type": "tidelift"
}
],
"time": "2023-12-13T10:59:42+00:00"
"time": "2024-01-05T15:50:47+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",

View File

@@ -63,6 +63,7 @@ use FireflyIII\Support\Binder\TagList;
use FireflyIII\Support\Binder\TagOrId;
use FireflyIII\Support\Binder\UserGroupAccount;
use FireflyIII\Support\Binder\UserGroupBill;
use FireflyIII\Support\Binder\UserGroupTransaction;
use FireflyIII\TransactionRules\Actions\AddTag;
use FireflyIII\TransactionRules\Actions\AppendDescription;
use FireflyIII\TransactionRules\Actions\AppendDescriptionToNotes;
@@ -114,7 +115,7 @@ return [
'handle_debts' => true,
// see cer.php for exchange rates feature flag.
],
'version' => '6.1.2',
'version' => '6.1.6',
'api_version' => '2.0.12',
'db_version' => 22,
@@ -433,60 +434,61 @@ return [
'bindables' => [
// models
'account' => Account::class,
'attachment' => Attachment::class,
'availableBudget' => AvailableBudget::class,
'bill' => Bill::class,
'budget' => Budget::class,
'budgetLimit' => BudgetLimit::class,
'category' => Category::class,
'linkType' => LinkType::class,
'transactionType' => TransactionTypeModel::class,
'journalLink' => TransactionJournalLink::class,
'currency' => TransactionCurrency::class,
'objectGroup' => ObjectGroup::class,
'piggyBank' => PiggyBank::class,
'preference' => Preference::class,
'tj' => TransactionJournal::class,
'tag' => Tag::class,
'recurrence' => Recurrence::class,
'rule' => Rule::class,
'ruleGroup' => RuleGroup::class,
'transactionGroup' => TransactionGroup::class,
'user' => User::class,
'webhook' => Webhook::class,
'webhookMessage' => WebhookMessage::class,
'webhookAttempt' => WebhookAttempt::class,
'invitedUser' => InvitedUser::class,
'account' => Account::class,
'attachment' => Attachment::class,
'availableBudget' => AvailableBudget::class,
'bill' => Bill::class,
'budget' => Budget::class,
'budgetLimit' => BudgetLimit::class,
'category' => Category::class,
'linkType' => LinkType::class,
'transactionType' => TransactionTypeModel::class,
'journalLink' => TransactionJournalLink::class,
'currency' => TransactionCurrency::class,
'objectGroup' => ObjectGroup::class,
'piggyBank' => PiggyBank::class,
'preference' => Preference::class,
'tj' => TransactionJournal::class,
'tag' => Tag::class,
'recurrence' => Recurrence::class,
'rule' => Rule::class,
'ruleGroup' => RuleGroup::class,
'transactionGroup' => TransactionGroup::class,
'user' => User::class,
'webhook' => Webhook::class,
'webhookMessage' => WebhookMessage::class,
'webhookAttempt' => WebhookAttempt::class,
'invitedUser' => InvitedUser::class,
// strings
'currency_code' => CurrencyCode::class,
'currency_code' => CurrencyCode::class,
// dates
'start_date' => Date::class,
'end_date' => Date::class,
'date' => Date::class,
'start_date' => Date::class,
'end_date' => Date::class,
'date' => Date::class,
// lists
'accountList' => AccountList::class,
'doubleList' => AccountList::class,
'budgetList' => BudgetList::class,
'journalList' => JournalList::class,
'categoryList' => CategoryList::class,
'tagList' => TagList::class,
'accountList' => AccountList::class,
'doubleList' => AccountList::class,
'budgetList' => BudgetList::class,
'journalList' => JournalList::class,
'categoryList' => CategoryList::class,
'tagList' => TagList::class,
// others
'fromCurrencyCode' => CurrencyCode::class,
'toCurrencyCode' => CurrencyCode::class,
'cliToken' => CLIToken::class,
'tagOrId' => TagOrId::class,
'dynamicConfigKey' => DynamicConfigKey::class,
'eitherConfigKey' => EitherConfigKey::class,
'fromCurrencyCode' => CurrencyCode::class,
'toCurrencyCode' => CurrencyCode::class,
'cliToken' => CLIToken::class,
'tagOrId' => TagOrId::class,
'dynamicConfigKey' => DynamicConfigKey::class,
'eitherConfigKey' => EitherConfigKey::class,
// V2 API endpoints:
'userGroupAccount' => UserGroupAccount::class,
'userGroupBill' => UserGroupBill::class,
'userGroup' => UserGroup::class,
'userGroupAccount' => UserGroupAccount::class,
'userGroupTransaction' => UserGroupTransaction::class,
'userGroupBill' => UserGroupBill::class,
'userGroup' => UserGroup::class,
],
'rule-actions' => [
'set_category' => SetCategory::class,

View File

@@ -210,8 +210,10 @@ return [
'amount_exactly' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
'amount_less' => ['alias' => false, 'needs_context' => true],
'amount_max' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
'less' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
'amount_more' => ['alias' => false, 'needs_context' => true],
'amount_min' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
'more' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
'foreign_amount_is' => ['alias' => false, 'needs_context' => true],
'foreign_amount' => ['alias' => true, 'alias_for' => 'foreign_amount_is', 'needs_context' => true],
'foreign_amount_less' => ['alias' => false, 'needs_context' => true],

26
package-lock.json generated
View File

@@ -443,12 +443,12 @@
"dev": true
},
"node_modules/axios": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz",
"integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==",
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.15.0",
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@@ -578,9 +578,9 @@
}
},
"node_modules/date-fns": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.0.6.tgz",
"integrity": "sha512-W+G99rycpKMMF2/YD064b2lE7jJGUe+EjOES7Q8BIGY8sbNdbgcs9XFTZwvzc9Jx1f3k7LB7gZaZa7f8Agzljg==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.1.0.tgz",
"integrity": "sha512-ZO7yefXV/wCWzd3I9haCHmfzlfA3i1a2HHO7ZXjtJrRjXt8FULKJ2Vl8wji3XYF4dQ0ZJ/tokXDZeYlFvgms9Q==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -860,9 +860,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
"version": "8.4.33",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
"dev": true,
"funding": [
{
@@ -922,9 +922,9 @@
}
},
"node_modules/sass": {
"version": "1.69.6",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.69.6.tgz",
"integrity": "sha512-qbRr3k9JGHWXCvZU77SD2OTwUlC+gNT+61JOLcmLm+XqH4h/5D+p4IIsxvpkB89S9AwJOyb5+rWNpIucaFxSFQ==",
"version": "1.69.7",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz",
"integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
import{a as s}from"./get-c53daca3.js";class p{list(a){return s.get("/api/v2/transactions",{params:a})}show(a,t){return s.get("/api/v2/transactions/"+a,{params:t})}}export{p as G};

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