mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-01-25 15:05:13 +00:00
Compare commits
22 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
158081395b | ||
|
|
34a7fd3ef0 | ||
|
|
96aafacf43 | ||
|
|
035d599910 | ||
|
|
f5a929d72e | ||
|
|
22b97ce8ef | ||
|
|
832019792f | ||
|
|
76b8ff18b0 | ||
|
|
8c0a82ac0a | ||
|
|
7edc386cdd | ||
|
|
5437d07ec2 | ||
|
|
ef3a1401dd | ||
|
|
aa6169e314 | ||
|
|
4a4f1ff055 | ||
|
|
844470bf08 | ||
|
|
92e985a9b8 | ||
|
|
70e11098af | ||
|
|
e76ab21091 | ||
|
|
87644923cf | ||
|
|
c46e9519c2 | ||
|
|
775933c3e8 | ||
|
|
5e316a1f05 |
76
.ci/php-cs-fixer/composer.lock
generated
76
.ci/php-cs-fixer/composer.lock
generated
@@ -402,16 +402,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.92.5",
|
||||
"version": "v3.93.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58"
|
||||
"reference": "50895a07cface1385082e4caa6a6786c4e033468"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58",
|
||||
"reference": "260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/50895a07cface1385082e4caa6a6786c4e033468",
|
||||
"reference": "50895a07cface1385082e4caa6a6786c4e033468",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -443,14 +443,14 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"facile-it/paraunit": "^1.3.1 || ^2.7",
|
||||
"infection/infection": "^0.31",
|
||||
"infection/infection": "^0.32",
|
||||
"justinrainbow/json-schema": "^6.6",
|
||||
"keradus/cli-executor": "^2.3",
|
||||
"mikey179/vfsstream": "^1.6.12",
|
||||
"php-coveralls/php-coveralls": "^2.9",
|
||||
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
|
||||
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
|
||||
"phpunit/phpunit": "^9.6.31 || ^10.5.60 || ^11.5.46",
|
||||
"phpunit/phpunit": "^9.6.31 || ^10.5.60 || ^11.5.48",
|
||||
"symfony/polyfill-php85": "^1.33",
|
||||
"symfony/var-dumper": "^5.4.48 || ^6.4.26 || ^7.4.0 || ^8.0",
|
||||
"symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0"
|
||||
@@ -494,7 +494,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.92.5"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.93.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -502,7 +502,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-08T21:57:37+00:00"
|
||||
"time": "2026-01-23T17:33:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -1252,16 +1252,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v8.0.3",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587"
|
||||
"reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/6145b304a5c1ea0bdbd0b04d297a5864f9a7d587",
|
||||
"reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b",
|
||||
"reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1318,7 +1318,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.3"
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1338,7 +1338,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-23T14:52:06+00:00"
|
||||
"time": "2026-01-13T13:06:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -1409,16 +1409,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v8.0.0",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "573f95783a2ec6e38752979db139f09fec033f03"
|
||||
"reference": "99301401da182b6cfaa4700dbe9987bb75474b47"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03",
|
||||
"reference": "573f95783a2ec6e38752979db139f09fec033f03",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47",
|
||||
"reference": "99301401da182b6cfaa4700dbe9987bb75474b47",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1470,7 +1470,7 @@
|
||||
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v8.0.0"
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1490,7 +1490,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-30T14:17:19+00:00"
|
||||
"time": "2026-01-05T11:45:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
@@ -1640,16 +1640,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v8.0.3",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12"
|
||||
"reference": "42e48eb02e07d5f3771d194d67da117eb824c8c1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/dd3a2953570a283a2ba4e17063bb98c734cf5b12",
|
||||
"reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/42e48eb02e07d5f3771d194d67da117eb824c8c1",
|
||||
"reference": "42e48eb02e07d5f3771d194d67da117eb824c8c1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1684,7 +1684,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.3"
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1704,7 +1704,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-23T14:52:06+00:00"
|
||||
"time": "2026-01-12T12:37:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -2358,16 +2358,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v8.0.3",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "0cbbd88ec836f8757641c651bb995335846abb78"
|
||||
"reference": "10df72602d88c0a3fa685b822976a052611dd607"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/0cbbd88ec836f8757641c651bb995335846abb78",
|
||||
"reference": "0cbbd88ec836f8757641c651bb995335846abb78",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/10df72602d88c0a3fa685b822976a052611dd607",
|
||||
"reference": "10df72602d88c0a3fa685b822976a052611dd607",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2399,7 +2399,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.3"
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2419,7 +2419,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-19T10:01:18+00:00"
|
||||
"time": "2026-01-23T11:07:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -2576,16 +2576,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v8.0.1",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
|
||||
"reference": "758b372d6882506821ed666032e43020c4f57194"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
|
||||
"reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194",
|
||||
"reference": "758b372d6882506821ed666032e43020c4f57194",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2642,7 +2642,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.1"
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2662,7 +2662,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-01T09:13:36+00:00"
|
||||
"time": "2026-01-12T12:37:40+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
||||
@@ -158,7 +158,10 @@ class TagController extends Controller
|
||||
'currency_id' => (string) $foreignCurrencyId,
|
||||
'currency_code' => $journal['foreign_currency_code'],
|
||||
];
|
||||
$response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount']));
|
||||
$response[$foreignKey]['difference'] = bcadd(
|
||||
(string) $response[$foreignKey]['difference'],
|
||||
Steam::positive($journal['foreign_amount'])
|
||||
);
|
||||
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,10 @@ class TagController extends Controller
|
||||
'currency_id' => (string) $foreignCurrencyId,
|
||||
'currency_code' => $journal['foreign_currency_code'],
|
||||
];
|
||||
$response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount']));
|
||||
$response[$foreignKey]['difference'] = bcadd(
|
||||
(string) $response[$foreignKey]['difference'],
|
||||
Steam::positive($journal['foreign_amount'])
|
||||
);
|
||||
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace FireflyIII\Api\V1\Controllers\Models\Transaction;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Transaction\StoreRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
@@ -87,9 +88,9 @@ class StoreController extends Controller
|
||||
public function store(StoreRequest $request): JsonResponse
|
||||
{
|
||||
Log::debug('Now in API StoreController::store()');
|
||||
$data = $request->getAll();
|
||||
$data['user'] = auth()->user();
|
||||
$data['user_group'] = $this->userGroup;
|
||||
$data = $request->getAll();
|
||||
$data['user'] = auth()->user();
|
||||
$data['user_group'] = $this->userGroup;
|
||||
|
||||
Log::channel('audit')->info('Store new transaction over API.', $data);
|
||||
|
||||
@@ -109,18 +110,21 @@ class StoreController extends Controller
|
||||
throw new ValidationException($validator);
|
||||
}
|
||||
Preferences::mark();
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
$flags->applyRules = $data['apply_rules'] ?? true;
|
||||
$flags->fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
$flags->batchSubmission = $data['batch_submission'] ?? false;
|
||||
Log::debug('CreatedSingleTransactionGroup');
|
||||
event(new CreatedSingleTransactionGroup($transactionGroup, $flags));
|
||||
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setUser($admin)
|
||||
->setUserGroup($this->userGroup)
|
||||
@@ -130,20 +134,20 @@ class StoreController extends Controller
|
||||
->withAPIInformation()
|
||||
;
|
||||
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
if (null === $selectedGroup) {
|
||||
throw HttpException::fromStatusCode(410, '200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
|
||||
}
|
||||
|
||||
// enrich
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
|
||||
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
$resource = new Item($selectedGroup, $transformer, 'transactions');
|
||||
$resource = new Item($selectedGroup, $transformer, 'transactions');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,9 @@ class UpdateController extends Controller
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
$runRecalculations = $oldHash !== $newHash;
|
||||
|
||||
// FIXME responds to a single event.
|
||||
// flags in array?
|
||||
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $runRecalculations));
|
||||
|
||||
/** @var User $admin */
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Webhook;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\Webhook;
|
||||
@@ -176,8 +176,8 @@ class ShowController extends Controller
|
||||
}
|
||||
|
||||
// trigger event to send them:
|
||||
Log::debug('send event RequestedSendWebhookMessages from ShowController::triggerTransaction()');
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$fields = ['order' => ['order', 'convertInteger']];
|
||||
$fields = ['order' => ['order', 'convertInteger']];
|
||||
$data = $this->getAllData($fields);
|
||||
$data['name'] = $this->convertString('name');
|
||||
$data['accounts'] = $this->parseAccounts($this->get('accounts'));
|
||||
|
||||
@@ -64,6 +64,7 @@ class StoreRequest extends FormRequest
|
||||
return [
|
||||
'group_title' => $this->convertString('group_title'),
|
||||
'error_if_duplicate_hash' => $this->boolean('error_if_duplicate_hash'),
|
||||
'batch_submission' => $this->boolean('batch_submission'),
|
||||
'apply_rules' => $this->boolean('apply_rules', true),
|
||||
'fire_webhooks' => $this->boolean('fire_webhooks', true),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
|
||||
@@ -113,7 +113,7 @@ class UpdateRequest extends FormRequest
|
||||
];
|
||||
$this->booleanFields = ['reconciled'];
|
||||
$this->arrayFields = ['tags'];
|
||||
$data = [];
|
||||
$data = ['batch_submission' => false];
|
||||
if ($this->has('transactions')) {
|
||||
$data['transactions'] = $this->getTransactionData();
|
||||
}
|
||||
@@ -123,6 +123,9 @@ class UpdateRequest extends FormRequest
|
||||
if ($this->has('fire_webhooks')) {
|
||||
$data['fire_webhooks'] = $this->boolean('fire_webhooks', true);
|
||||
}
|
||||
if ($this->has('batch_submission')) {
|
||||
$data['batch_submission'] = $this->boolean('batch_submission');
|
||||
}
|
||||
if ($this->has('group_title')) {
|
||||
$data['group_title'] = $this->convertString('group_title');
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ class CorrectsGroupAccounts extends Command
|
||||
foreach ($groups as $groupId) {
|
||||
$group = TransactionGroup::find($groupId);
|
||||
// TODO in theory the "unifyAccounts" method could lead to the need for run recalculations.
|
||||
// FIXME needs to be a collection.
|
||||
$event = new UpdatedTransactionGroup($group, true, true, false);
|
||||
$handler->unifyAccounts($event);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class CorrectsMetaDataFields extends Command
|
||||
|
||||
private function rename(string $original, string $update): void
|
||||
{
|
||||
$total = DB::table('journal_meta')->where('name', '=', $original)->update(['name' => $update]);
|
||||
$total = DB::table('journal_meta')->where('name', '=', $original)->update(['name' => $update]);
|
||||
$this->count += $total;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,11 @@ class UpgradesTransferCurrencies extends Command
|
||||
{
|
||||
if (null === $this->sourceTransaction->transaction_currency_id && $this->sourceCurrency instanceof TransactionCurrency) {
|
||||
$this->sourceTransaction->transaction_currency_id = $this->sourceCurrency->id;
|
||||
$message = sprintf('Transaction #%d has no currency setting, now set to %s.', $this->sourceTransaction->id, $this->sourceCurrency->code);
|
||||
$message = sprintf(
|
||||
'Transaction #%d has no currency setting, now set to %s.',
|
||||
$this->sourceTransaction->id,
|
||||
$this->sourceCurrency->code
|
||||
);
|
||||
$this->friendlyInfo($message);
|
||||
++$this->count;
|
||||
$this->sourceTransaction->save();
|
||||
@@ -335,7 +339,11 @@ class UpgradesTransferCurrencies extends Command
|
||||
{
|
||||
if (null === $this->destinationTransaction->transaction_currency_id && $this->destinationCurrency instanceof TransactionCurrency) {
|
||||
$this->destinationTransaction->transaction_currency_id = $this->destinationCurrency->id;
|
||||
$message = sprintf('Transaction #%d has no currency setting, now set to %s.', $this->destinationTransaction->id, $this->destinationCurrency->code);
|
||||
$message = sprintf(
|
||||
'Transaction #%d has no currency setting, now set to %s.',
|
||||
$this->destinationTransaction->id,
|
||||
$this->destinationCurrency->code
|
||||
);
|
||||
$this->friendlyInfo($message);
|
||||
++$this->count;
|
||||
$this->destinationTransaction->save();
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* CreatedSingleTransactionGroup.php
|
||||
* Copyright (c) 2026 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CreatedSingleTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public TransactionGroup $transactionGroup,
|
||||
public TransactionGroupEventFlags $flags
|
||||
) {
|
||||
Log::debug(__METHOD__);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* CreatedTransactionGroupBatch.php
|
||||
* Copyright (c) 2026 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class CreatedTransactionGroupInBatch extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public Collection $collection,
|
||||
public array $flags
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* TransactionGroupEventFlags.php
|
||||
* Copyright (c) 2026 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
class TransactionGroupEventFlags
|
||||
{
|
||||
public bool $applyRules = true;
|
||||
public bool $fireWebhooks = true;
|
||||
public bool $batchSubmission = false;
|
||||
public bool $recalculateCredit = true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* TransactionGroupRequestsAuditLogEntry.php
|
||||
* Copyright (c) 2026 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TransactionGroupRequestsAuditLogEntry extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public Model $changer,
|
||||
public Model $auditable,
|
||||
public string $field,
|
||||
public mixed $before,
|
||||
public mixed $after
|
||||
) {}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RequestedReportOnJournals.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* TransactionGroupsRequestedReporting.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,24 +22,14 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use FireflyIII\Events\Event;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class RequestedReportOnJournals
|
||||
*/
|
||||
class RequestedReportOnJournals
|
||||
class TransactionGroupsRequestedReporting extends Event
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithSockets;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
@@ -46,15 +38,5 @@ class RequestedReportOnJournals
|
||||
public function __construct(
|
||||
public int $userId,
|
||||
public Collection $groups
|
||||
) {
|
||||
Log::debug('In event RequestedReportOnJournals.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*/
|
||||
public function broadcastOn(): PrivateChannel
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
) {}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* RequestedSendWebhookMessages.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
* WebhookMessagesRequestSending.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,16 +22,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
namespace FireflyIII\Events\Model\Webhook;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class RequestedSendWebhookMessages
|
||||
*/
|
||||
class RequestedSendWebhookMessages extends Event
|
||||
class WebhookMessagesRequestSending extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
}
|
||||
38
app/Events/Security/System/NewInvitationCreated.php
Normal file
38
app/Events/Security/System/NewInvitationCreated.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* NewInvitationCreated.php
|
||||
* Copyright (c) 2026 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Security\System;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\InvitedUser;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NewInvitationCreated extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
public InvitedUser $invitee
|
||||
) {}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RequestedVersionCheckStatus.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* SystemRequestedVersionCheck.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,24 +22,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
namespace FireflyIII\Events\Security\System;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class RequestedVersionCheckStatus
|
||||
*/
|
||||
class RequestedVersionCheckStatus extends Event
|
||||
class SystemRequestedVersionCheck extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance. This event is triggered when Firefly III wants to know
|
||||
* what the deal is with the version checker.
|
||||
*/
|
||||
public function __construct(
|
||||
public User $user
|
||||
) {}
|
||||
@@ -50,7 +50,6 @@ use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
|
||||
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\User;
|
||||
use FireflyIII\Validation\AccountValidator;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -110,22 +109,24 @@ class TransactionJournalFactory
|
||||
{
|
||||
Log::debug('Now in TransactionJournalFactory::create()');
|
||||
// convert to special object.
|
||||
$dataObject = new NullArrayObject($data);
|
||||
// $dataObject = new NullArrayObject($data);
|
||||
|
||||
Log::debug('Start of TransactionJournalFactory::create()');
|
||||
$collection = new Collection();
|
||||
$transactions = $dataObject['transactions'] ?? [];
|
||||
$collection = new Collection();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
if (0 === count($transactions)) {
|
||||
Log::error('There are no transactions in the array, the TransactionJournalFactory cannot continue.');
|
||||
|
||||
return new Collection();
|
||||
}
|
||||
$batchSubmission = $data['batch_submission'] ?? false;
|
||||
|
||||
try {
|
||||
/** @var array $row */
|
||||
foreach ($transactions as $index => $row) {
|
||||
$row['batch_submission'] = $batchSubmission;
|
||||
Log::debug(sprintf('Now creating journal %d/%d', $index + 1, count($transactions)));
|
||||
$journal = $this->createJournal(new NullArrayObject($row));
|
||||
$journal = $this->createJournal($row);
|
||||
if ($journal instanceof TransactionJournal) {
|
||||
$collection->push($journal);
|
||||
}
|
||||
@@ -161,7 +162,7 @@ class TransactionJournalFactory
|
||||
*
|
||||
* @SuppressWarnings("PHPMD.ExcessiveMethodLength")
|
||||
*/
|
||||
private function createJournal(NullArrayObject $row): ?TransactionJournal
|
||||
private function createJournal(array $row): ?TransactionJournal
|
||||
{
|
||||
Log::debug('Now in TransactionJournalFactory::createJournal()');
|
||||
$row['import_hash_v2'] = $this->hashArray($row);
|
||||
@@ -273,7 +274,7 @@ class TransactionJournalFactory
|
||||
'date_tz' => $carbon->format('e'),
|
||||
'order' => $order,
|
||||
'tag_count' => 0,
|
||||
'completed' => 0,
|
||||
'completed' => !$row['batch_submission'],
|
||||
]);
|
||||
Log::debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description));
|
||||
|
||||
@@ -331,7 +332,7 @@ class TransactionJournalFactory
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
$journal->completed = true;
|
||||
Log::debug(sprintf('Is part of a batch submission? %s', var_export($row['batch_submission'], true)));
|
||||
$journal->save();
|
||||
$this->storeBudget($journal, $row);
|
||||
$this->storeCategory($journal, $row);
|
||||
@@ -344,20 +345,18 @@ class TransactionJournalFactory
|
||||
return $journal;
|
||||
}
|
||||
|
||||
private function hashArray(NullArrayObject $row): string
|
||||
private function hashArray(array $row): string
|
||||
{
|
||||
$dataRow = $row->getArrayCopy();
|
||||
|
||||
unset($dataRow['import_hash_v2'], $dataRow['original_source']);
|
||||
unset($row['import_hash_v2'], $row['original_source']);
|
||||
|
||||
try {
|
||||
$json = json_encode($dataRow, JSON_THROW_ON_ERROR);
|
||||
$json = json_encode($row, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
Log::error(sprintf('Could not encode dataRow: %s', $e->getMessage()));
|
||||
$json = microtime();
|
||||
}
|
||||
$hash = hash('sha256', $json);
|
||||
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
|
||||
$hash = hash('sha256', $json);
|
||||
Log::debug(sprintf('The hash is: %s', $hash), $row);
|
||||
|
||||
return $hash;
|
||||
}
|
||||
@@ -399,7 +398,7 @@ class TransactionJournalFactory
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function validateAccounts(NullArrayObject $data): void
|
||||
private function validateAccounts(array $data): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$transactionType = $data['type'] ?? 'invalid';
|
||||
@@ -577,7 +576,7 @@ class TransactionJournalFactory
|
||||
/**
|
||||
* Link a piggy bank to this journal.
|
||||
*/
|
||||
private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void
|
||||
private function storePiggyEvent(TransactionJournal $journal, array $data): void
|
||||
{
|
||||
Log::debug('Will now store piggy event.');
|
||||
|
||||
@@ -592,17 +591,17 @@ class TransactionJournalFactory
|
||||
Log::debug('Create no piggy event');
|
||||
}
|
||||
|
||||
private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
|
||||
private function storeMetaFields(TransactionJournal $journal, array $transaction): void
|
||||
{
|
||||
foreach ($this->fields as $field) {
|
||||
$this->storeMeta($journal, $transaction, $field);
|
||||
}
|
||||
}
|
||||
|
||||
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
|
||||
protected function storeMeta(TransactionJournal $journal, array $data, string $field): void
|
||||
{
|
||||
$set = ['journal' => $journal, 'name' => $field, 'data' => (string) ($data[$field] ?? '')];
|
||||
if ($data[$field] instanceof Carbon) {
|
||||
if (array_key_exists($field, $data) && $data[$field] instanceof Carbon) {
|
||||
$data[$field]->setTimezone(config('app.timezone'));
|
||||
Log::debug(sprintf('%s Date: %s (%s)', $field, $data[$field], $data[$field]->timezone->getName()));
|
||||
$set['data'] = $data[$field]->format('Y-m-d H:i:s');
|
||||
@@ -615,7 +614,7 @@ class TransactionJournalFactory
|
||||
$factory->updateOrCreate($set);
|
||||
}
|
||||
|
||||
private function storeLocation(TransactionJournal $journal, NullArrayObject $data): void
|
||||
private function storeLocation(TransactionJournal $journal, array $data): void
|
||||
{
|
||||
if (!in_array(null, [$data['longitude'], $data['latitude'], $data['zoom_level']], true)) {
|
||||
$location = new Location();
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\DestroyedTransactionGroup;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
|
||||
@@ -56,8 +56,8 @@ class DestroyedGroupEventHandler
|
||||
$engine->setObjects(new Collection()->push($group));
|
||||
$engine->setTrigger(WebhookTrigger::DESTROY_TRANSACTION);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
|
||||
private function updateRunningBalance(DestroyedTransactionGroup $event): void
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TriggeredStoredTransactionGroup;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
@@ -47,16 +47,16 @@ class StoredGroupEventHandler
|
||||
{
|
||||
public function runAllHandlers(StoredTransactionGroup $event): void
|
||||
{
|
||||
$this->processRules($event, null);
|
||||
$this->recalculateCredit($event);
|
||||
$this->triggerWebhooks($event);
|
||||
// $this->processRules($event, null);
|
||||
// $this->recalculateCredit($event);
|
||||
// $this->triggerWebhooks($event);
|
||||
$this->removePeriodStatistics($event);
|
||||
}
|
||||
|
||||
public function triggerRulesManually(TriggeredStoredTransactionGroup $event): void
|
||||
{
|
||||
$newEvent = new StoredTransactionGroup($event->transactionGroup, true, false);
|
||||
$this->processRules($newEvent, $event->ruleGroup);
|
||||
// $newEvent = new StoredTransactionGroup($event->transactionGroup, true, false);
|
||||
// $this->processRules($newEvent, $event->ruleGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +181,7 @@ class StoredGroupEventHandler
|
||||
$engine->generateMessages();
|
||||
|
||||
// trigger event to send them:
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -207,8 +207,8 @@ class UpdatedGroupEventHandler
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_TRANSACTION);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
|
||||
private function updateRunningBalance(UpdatedTransactionGroup $event): void
|
||||
|
||||
@@ -25,7 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
@@ -58,8 +58,8 @@ class BudgetLimitObserver
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +101,8 @@ class BudgetLimitObserver
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Budget;
|
||||
@@ -59,8 +59,8 @@ class BudgetObserver
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ class BudgetObserver
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +97,8 @@ class BudgetObserver
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::DESTROY_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
|
||||
$repository = app(AttachmentRepositoryInterface::class);
|
||||
$repository->setUser($budget->user);
|
||||
|
||||
@@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
@@ -40,19 +39,8 @@ class TransactionObserver
|
||||
|
||||
public function created(Transaction $transaction): void
|
||||
{
|
||||
Log::debug('Observe "created" of a transaction.');
|
||||
if (
|
||||
true === FireflyConfig::get('use_running_balance', config('firefly.feature_flags.running_balance_column'))->data && (
|
||||
1 === bccomp($transaction->amount, '0')
|
||||
&& self::$recalculate
|
||||
)
|
||||
) {
|
||||
Log::debug('Trigger recalculateForJournal');
|
||||
$journal = $transaction->transactionJournal;
|
||||
if ($journal instanceof TransactionJournal) {
|
||||
AccountBalanceCalculator::recalculateForJournal($journal);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
$this->updatePrimaryCurrencyAmount($transaction);
|
||||
}
|
||||
|
||||
|
||||
@@ -773,30 +773,22 @@ trait MetaCollection
|
||||
$this->query->whereNotNull('tag_transaction_journal.tag_id');
|
||||
|
||||
// Added this while fixing #10898, not sure why a post filter was ever necessary.
|
||||
$this->query->whereIn('tag_transaction_journal.tag_id', $tags->pluck('id')->toArray());
|
||||
// Removed again for #11473 because it breaks multiple tag filters.
|
||||
// $this->query->whereIn('tag_transaction_journal.tag_id', $tags->pluck('id')->toArray());
|
||||
|
||||
// this method adds a "postFilter" to the collector.
|
||||
$list = $tags->pluck('tag')->toArray();
|
||||
$list = array_map(strtolower(...), $list);
|
||||
$filter = static function (array $object) use ($list): bool {
|
||||
Log::debug(sprintf('Now in setTags(%s) filter', implode(', ', $list)));
|
||||
Log::debug(sprintf('Now in setTags (any) filter: %s', implode(', ', $list)));
|
||||
foreach ($object['transactions'] as $transaction) {
|
||||
$total = count($transaction['tags']);
|
||||
$matched = 0;
|
||||
foreach ($transaction['tags'] as $tag) {
|
||||
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
|
||||
if (in_array(strtolower((string) $tag['name']), $list, true)) {
|
||||
Log::debug(sprintf('Transaction has tag "%s" so return true.', $tag['name']));
|
||||
++$matched;
|
||||
if (1 === count($list)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($list) > 1 && $total === $matched && $matched === count($list)) {
|
||||
Log::debug(sprintf('All %d searched tags are present.', $total));
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::debug('Transaction has no tags from the list, so return false.');
|
||||
|
||||
@@ -433,6 +433,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
*/
|
||||
public function getGroups(): Collection
|
||||
{
|
||||
Log::debug('Now in getGroups()');
|
||||
if ($this->expandGroupSearch) {
|
||||
// get group ID's for the query:
|
||||
$groupIds = $this->getCollectedGroupIds();
|
||||
@@ -440,6 +441,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$this->query->orWhereIn('transaction_journals.transaction_group_id', $groupIds);
|
||||
}
|
||||
$result = $this->query->get($this->fields);
|
||||
// $this->dumpQueryInLogs();
|
||||
// Log::debug(sprintf('Count of result is %d', $result->count()));
|
||||
// now to parse this into an array.
|
||||
$collection = $this->parseArray($result);
|
||||
|
||||
@@ -758,6 +761,12 @@ class GroupCollector implements GroupCollectorInterface
|
||||
count($currentCollection)
|
||||
));
|
||||
|
||||
if (0 === $currentCollection->count()) {
|
||||
Log::debug('Found nothing anyway, return empty collection.');
|
||||
|
||||
return $currentCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Closure $function
|
||||
*/
|
||||
@@ -775,16 +784,25 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$result = $function($item);
|
||||
if (false === $result) {
|
||||
// skip other filters, continue to next item.
|
||||
Log::debug('Result is false');
|
||||
|
||||
continue;
|
||||
}
|
||||
// if the result is a bool, use the unedited results.
|
||||
if (true === $result) {
|
||||
Log::debug('Result is true');
|
||||
$nextCollection->push($item);
|
||||
|
||||
continue;
|
||||
}
|
||||
// if the result is an array, the filter has changed what's being returned.
|
||||
if (is_array($result)) {
|
||||
Log::debug('Result is array');
|
||||
$nextCollection->push($result);
|
||||
|
||||
continue;
|
||||
}
|
||||
Log::debug('Result is something else!');
|
||||
}
|
||||
$currentCollection = $nextCollection;
|
||||
Log::debug(sprintf('GroupCollector: postFilterCollection has %d transaction(s) left.', count($currentCollection)));
|
||||
@@ -827,6 +845,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
*/
|
||||
public function getPaginatedGroups(): LengthAwarePaginator
|
||||
{
|
||||
Log::debug('Now in getPaginatedGroups()');
|
||||
$set = $this->getGroups();
|
||||
if (0 === $this->limit) {
|
||||
$this->setLimit(50);
|
||||
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
use FireflyIII\Events\Admin\InvitationCreated;
|
||||
use FireflyIII\Events\Security\System\NewInvitationCreated;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
@@ -202,7 +202,7 @@ class UserController extends Controller
|
||||
session()->flash('info', trans('firefly.user_is_invited', ['address' => $address]));
|
||||
|
||||
// event!
|
||||
event(new InvitationCreated($invitee));
|
||||
event(new NewInvitationCreated($invitee));
|
||||
|
||||
return redirect(route('settings.users'));
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ class LoginController extends Controller
|
||||
*/
|
||||
protected function sendFailedLoginResponse(Request $request): void
|
||||
{
|
||||
$exception = ValidationException::withMessages([$this->username() => [trans('auth.failed')]]);
|
||||
$exception = ValidationException::withMessages([$this->username() => [trans('auth.failed')]]);
|
||||
$exception->redirectTo = route('login');
|
||||
|
||||
throw $exception;
|
||||
|
||||
@@ -192,7 +192,10 @@ class IndexController extends Controller
|
||||
if (count($bill['paid_dates']) < count($bill['pay_dates'])) {
|
||||
$count = count($bill['pay_dates']) - count($bill['paid_dates']);
|
||||
if ($count > 0) {
|
||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
||||
$avg = bcdiv(
|
||||
bcadd((string) $bill['amount_min'], (string) $bill['amount_max']),
|
||||
'2'
|
||||
);
|
||||
$avg = bcmul($avg, (string) $count);
|
||||
$sums[$groupOrder][$currencyId]['total_left_to_pay'] = bcadd($sums[$groupOrder][$currencyId]['total_left_to_pay'], $avg);
|
||||
Log::debug(
|
||||
|
||||
@@ -197,7 +197,13 @@ class BudgetLimitController extends Controller
|
||||
if ($request->expectsJson()) {
|
||||
$array = $limit->toArray();
|
||||
// add some extra metadata:
|
||||
$spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection()->push($budget), $currency);
|
||||
$spentArr = $this->opsRepository->sumExpenses(
|
||||
$limit->start_date,
|
||||
$limit->end_date,
|
||||
null,
|
||||
new Collection()->push($budget),
|
||||
$currency
|
||||
);
|
||||
$array['spent'] = $spentArr[$currency->id]['sum'] ?? '0';
|
||||
$array['left_formatted'] = Amount::formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount']));
|
||||
$array['amount_formatted'] = Amount::formatAnything($limit->transactionCurrency, $limit['amount']);
|
||||
|
||||
@@ -73,7 +73,7 @@ class BillController extends Controller
|
||||
*/
|
||||
foreach ($paid as $info) {
|
||||
$amount = $info['sum'];
|
||||
$label = (string) trans('firefly.paid_in_currency', ['currency' => $info['name']]);
|
||||
$label = (string) trans('firefly.paid_in_currency', ['currency' => $info['name']]);
|
||||
$chartData[$label] = ['amount' => $amount, 'currency_symbol' => $info['symbol'], 'currency_code' => $info['code']];
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class BillController extends Controller
|
||||
*/
|
||||
foreach ($unpaid as $info) {
|
||||
$amount = $info['sum'];
|
||||
$label = (string) trans('firefly.unpaid_in_currency', ['currency' => $info['name']]);
|
||||
$label = (string) trans('firefly.unpaid_in_currency', ['currency' => $info['name']]);
|
||||
$chartData[$label] = ['amount' => $amount, 'currency_symbol' => $info['symbol'], 'currency_code' => $info['code']];
|
||||
}
|
||||
|
||||
|
||||
@@ -539,7 +539,13 @@ class BudgetController extends Controller
|
||||
}
|
||||
|
||||
// get spent amount in this period for this currency.
|
||||
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency);
|
||||
$sum = $this->opsRepository->sumExpenses(
|
||||
$currentStart,
|
||||
$currentEnd,
|
||||
$accounts,
|
||||
new Collection()->push($budget),
|
||||
$currency
|
||||
);
|
||||
$amount = Steam::positive($sum[$currency->id]['sum'] ?? '0');
|
||||
$chartData[0]['entries'][$title] = Steam::bcround($amount, $currency->decimal_places);
|
||||
|
||||
|
||||
@@ -76,7 +76,11 @@ class TransactionController extends Controller
|
||||
foreach ($result as $journal) {
|
||||
$budget = $journal['budget_name'] ?? (string) trans('firefly.no_budget');
|
||||
$title = sprintf('%s (%s)', $budget, $journal['currency_symbol']);
|
||||
$data[$title] ??= ['amount' => '0', 'currency_symbol' => $journal['currency_symbol'], 'currency_code' => $journal['currency_code']];
|
||||
$data[$title] ??= [
|
||||
'amount' => '0',
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
];
|
||||
$data[$title]['amount'] = bcadd($data[$title]['amount'], (string) $journal['amount']);
|
||||
}
|
||||
$chart = $this->generator->multiCurrencyPieChart($data);
|
||||
@@ -122,7 +126,11 @@ class TransactionController extends Controller
|
||||
foreach ($result as $journal) {
|
||||
$category = $journal['category_name'] ?? (string) trans('firefly.no_category');
|
||||
$title = sprintf('%s (%s)', $category, $journal['currency_symbol']);
|
||||
$data[$title] ??= ['amount' => '0', 'currency_symbol' => $journal['currency_symbol'], 'currency_code' => $journal['currency_code']];
|
||||
$data[$title] ??= [
|
||||
'amount' => '0',
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
];
|
||||
$data[$title]['amount'] = bcadd($data[$title]['amount'], (string) $journal['amount']);
|
||||
}
|
||||
$chart = $this->generator->multiCurrencyPieChart($data);
|
||||
@@ -168,7 +176,11 @@ class TransactionController extends Controller
|
||||
foreach ($result as $journal) {
|
||||
$name = $journal['destination_account_name'];
|
||||
$title = sprintf('%s (%s)', $name, $journal['currency_symbol']);
|
||||
$data[$title] ??= ['amount' => '0', 'currency_symbol' => $journal['currency_symbol'], 'currency_code' => $journal['currency_code']];
|
||||
$data[$title] ??= [
|
||||
'amount' => '0',
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
];
|
||||
$data[$title]['amount'] = bcadd($data[$title]['amount'], (string) $journal['amount']);
|
||||
}
|
||||
$chart = $this->generator->multiCurrencyPieChart($data);
|
||||
@@ -214,7 +226,11 @@ class TransactionController extends Controller
|
||||
foreach ($result as $journal) {
|
||||
$name = $journal['source_account_name'];
|
||||
$title = sprintf('%s (%s)', $name, $journal['currency_symbol']);
|
||||
$data[$title] ??= ['amount' => '0', 'currency_symbol' => $journal['currency_symbol'], 'currency_code' => $journal['currency_code']];
|
||||
$data[$title] ??= [
|
||||
'amount' => '0',
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
];
|
||||
$data[$title]['amount'] = bcadd($data[$title]['amount'], (string) $journal['amount']);
|
||||
}
|
||||
$chart = $this->generator->multiCurrencyPieChart($data);
|
||||
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
@@ -152,10 +152,10 @@ abstract class Controller extends BaseController
|
||||
View::share('original_route_name', Route::currentRouteName());
|
||||
|
||||
// lottery to send any remaining webhooks:
|
||||
if (7 === random_int(1, 10)) {
|
||||
if (7 === random_int(1, 30)) {
|
||||
// trigger event to send them:
|
||||
Log::debug('send event RequestedSendWebhookMessages through lottery');
|
||||
event(new RequestedSendWebhookMessages());
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
View::share('darkMode', $darkMode);
|
||||
|
||||
@@ -27,7 +27,7 @@ use Carbon\Carbon;
|
||||
use Carbon\Exceptions\InvalidFormatException;
|
||||
use Exception;
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Events\Security\System\SystemRequestedVersionCheck;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Http\Middleware\Installer;
|
||||
@@ -178,7 +178,7 @@ class HomeController extends Controller
|
||||
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
event(new RequestedVersionCheckStatus($user));
|
||||
event(new SystemRequestedVersionCheck($user));
|
||||
|
||||
return view('index', [
|
||||
'count' => $count,
|
||||
@@ -202,7 +202,7 @@ class HomeController extends Controller
|
||||
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
event(new RequestedVersionCheckStatus($user));
|
||||
event(new SystemRequestedVersionCheck($user));
|
||||
|
||||
return view('index', ['subTitle' => $subTitle, 'start' => $start, 'end' => $end, 'pageTitle' => $pageTitle]);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,11 @@ class CategoryController extends Controller
|
||||
'categories' => [],
|
||||
];
|
||||
|
||||
$report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']] ??= ['spent' => '0', 'earned' => '0', 'sum' => '0'];
|
||||
$report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']] ??= [
|
||||
'spent' => '0',
|
||||
'earned' => '0',
|
||||
'sum' => '0',
|
||||
];
|
||||
$report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]['spent'] = bcadd(
|
||||
$report[$sourceAccountId]['currencies'][$currencyId]['categories'][$category['id']]['spent'],
|
||||
(string) $journal['amount']
|
||||
@@ -122,7 +126,11 @@ class CategoryController extends Controller
|
||||
'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
'categories' => [],
|
||||
];
|
||||
$report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']] ??= ['spent' => '0', 'earned' => '0', 'sum' => '0'];
|
||||
$report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']] ??= [
|
||||
'spent' => '0',
|
||||
'earned' => '0',
|
||||
'sum' => '0',
|
||||
];
|
||||
$report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]['earned'] = bcadd(
|
||||
$report[$destinationId]['currencies'][$currencyId]['categories'][$category['id']]['earned'],
|
||||
(string) $journal['amount']
|
||||
|
||||
@@ -24,7 +24,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
@@ -76,7 +77,9 @@ class CreateController extends Controller
|
||||
$newGroup = $service->cloneGroup($group);
|
||||
|
||||
// event!
|
||||
event(new StoredTransactionGroup($newGroup, true, true));
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
event(new CreatedSingleTransactionGroup($group, $flags));
|
||||
// event(new StoredTransactionGroup($newGroup, true, true));
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
@@ -107,29 +110,29 @@ class CreateController extends Controller
|
||||
{
|
||||
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';
|
||||
$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';
|
||||
|
||||
/** @var null|array $optionalFields */
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
|
||||
$accountToTypes = config('firefly.account_to_transaction');
|
||||
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
|
||||
$parts = parse_url((string) $previousUrl);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUrl = str_replace($search, '', $previousUrl);
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
|
||||
$accountToTypes = config('firefly.account_to_transaction');
|
||||
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
|
||||
$parts = parse_url((string) $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 = [
|
||||
$optionalDateFields = [
|
||||
'interest_date' => $optionalFields['interest_date'] ?? false,
|
||||
'book_date' => $optionalFields['book_date'] ?? false,
|
||||
'process_date' => $optionalFields['process_date'] ?? false,
|
||||
@@ -139,13 +142,13 @@ class CreateController extends Controller
|
||||
];
|
||||
$optionalFields['external_url'] ??= false;
|
||||
$optionalFields['location'] ??= false;
|
||||
$optionalFields['location']
|
||||
= $optionalFields['location'] && true === FireflyConfig::get('enable_external_map', config('firefly.enable_external_map'))->data;
|
||||
$optionalFields['location'] = $optionalFields['location']
|
||||
&& true === FireflyConfig::get('enable_external_map', config('firefly.enable_external_map'))->data;
|
||||
|
||||
// map info:
|
||||
$longitude = config('firefly.default_location.longitude');
|
||||
$latitude = config('firefly.default_location.latitude');
|
||||
$zoomLevel = config('firefly.default_location.zoom_level');
|
||||
$longitude = config('firefly.default_location.longitude');
|
||||
$latitude = config('firefly.default_location.latitude');
|
||||
$zoomLevel = config('firefly.default_location.zoom_level');
|
||||
|
||||
session()->put('preFilled', $preFilled);
|
||||
|
||||
|
||||
@@ -83,29 +83,29 @@ 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');
|
||||
$title = $transactionGroup->transactionJournals()->count() > 1
|
||||
$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';
|
||||
$cash = $repository->getCashAccount();
|
||||
$previousUrl = $this->rememberPreviousUrl('transactions.edit.url');
|
||||
$parts = parse_url((string) $previousUrl);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUrl = str_replace($search, '', $previousUrl);
|
||||
$subTitle = (string) trans('firefly.edit_transaction_title', ['description' => $title]);
|
||||
$subTitleIcon = 'fa-plus';
|
||||
$cash = $repository->getCashAccount();
|
||||
$previousUrl = $this->rememberPreviousUrl('transactions.edit.url');
|
||||
$parts = parse_url((string) $previousUrl);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUrl = str_replace($search, '', $previousUrl);
|
||||
|
||||
// settings necessary for v2
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
if (!is_array($optionalFields)) {
|
||||
$optionalFields = [];
|
||||
}
|
||||
// not really a fan of this, but meh.
|
||||
$optionalDateFields = [
|
||||
$optionalDateFields = [
|
||||
'interest_date' => $optionalFields['interest_date'] ?? false,
|
||||
'book_date' => $optionalFields['book_date'] ?? false,
|
||||
'process_date' => $optionalFields['process_date'] ?? false,
|
||||
@@ -115,13 +115,13 @@ class EditController extends Controller
|
||||
];
|
||||
$optionalFields['external_url'] ??= false;
|
||||
$optionalFields['location'] ??= false;
|
||||
$optionalFields['location']
|
||||
= $optionalFields['location'] && true === FireflyConfig::get('enable_external_map', config('firefly.enable_external_map'))->data;
|
||||
$optionalFields['location'] = $optionalFields['location']
|
||||
&& true === FireflyConfig::get('enable_external_map', config('firefly.enable_external_map'))->data;
|
||||
|
||||
// map info voor v2:
|
||||
$longitude = config('firefly.default_location.longitude');
|
||||
$latitude = config('firefly.default_location.latitude');
|
||||
$zoomLevel = config('firefly.default_location.zoom_level');
|
||||
$longitude = config('firefly.default_location.longitude');
|
||||
$latitude = config('firefly.default_location.latitude');
|
||||
$zoomLevel = config('firefly.default_location.zoom_level');
|
||||
|
||||
return view('transactions.edit', [
|
||||
'cash' => $cash,
|
||||
|
||||
@@ -78,7 +78,7 @@ class EditController extends Controller
|
||||
}
|
||||
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
$subTitle = (string) trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
|
||||
$subTitle = (string) trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
|
||||
$currency->symbol = htmlentities($currency->symbol);
|
||||
|
||||
// is currently enabled (for this user?)
|
||||
|
||||
@@ -23,34 +23,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http;
|
||||
|
||||
use FireflyIII\Http\Middleware\AcceptHeaders;
|
||||
use FireflyIII\Http\Middleware\Authenticate;
|
||||
use FireflyIII\Http\Middleware\Binder;
|
||||
use FireflyIII\Http\Middleware\EncryptCookies;
|
||||
use FireflyIII\Http\Middleware\InstallationId;
|
||||
use FireflyIII\Http\Middleware\Installer;
|
||||
use FireflyIII\Http\Middleware\InterestingMessage;
|
||||
use FireflyIII\Http\Middleware\IsAdmin;
|
||||
use FireflyIII\Http\Middleware\Range;
|
||||
use FireflyIII\Http\Middleware\RedirectIfAuthenticated;
|
||||
use FireflyIII\Http\Middleware\SecureHeaders;
|
||||
use FireflyIII\Http\Middleware\StartFireflySession;
|
||||
use FireflyIII\Http\Middleware\TrimStrings;
|
||||
use FireflyIII\Http\Middleware\TrustProxies;
|
||||
use FireflyIII\Http\Middleware\VerifyCsrfToken;
|
||||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
||||
use Illuminate\Auth\Middleware\Authorize;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||
use PragmaRX\Google2FALaravel\Middleware as MFAMiddleware;
|
||||
|
||||
/**
|
||||
* Class Kernel
|
||||
@@ -58,7 +45,7 @@ use PragmaRX\Google2FALaravel\Middleware as MFAMiddleware;
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
protected $middleware = [
|
||||
SecureHeaders::class,
|
||||
// SecureHeaders::class,
|
||||
CheckForMaintenanceMode::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
@@ -74,102 +61,5 @@ class Kernel extends HttpKernel
|
||||
'guest' => RedirectIfAuthenticated::class,
|
||||
'throttle' => ThrottleRequests::class,
|
||||
];
|
||||
protected $middlewareGroups = [
|
||||
// does not check login
|
||||
// does not check 2fa
|
||||
// does not check activation
|
||||
'web' => [
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
AuthenticateSession::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
|
||||
// only the basic variable binders.
|
||||
'binders-only' => [Installer::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, Binder::class],
|
||||
|
||||
// MUST NOT be logged in. Does not care about 2FA or confirmation.
|
||||
'user-not-logged-in' => [
|
||||
Installer::class,
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
Binder::class,
|
||||
RedirectIfAuthenticated::class,
|
||||
],
|
||||
// MUST be logged in.
|
||||
// MUST NOT have 2FA
|
||||
// don't care about confirmation:
|
||||
'user-logged-in-no-2fa' => [
|
||||
Installer::class,
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
Binder::class,
|
||||
Authenticate::class,
|
||||
// RedirectIfTwoFactorAuthenticated::class,
|
||||
],
|
||||
|
||||
// MUST be logged in
|
||||
// don't care about 2fa
|
||||
// don't care about confirmation.
|
||||
'user-simple-auth' => [
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
Binder::class,
|
||||
Authenticate::class,
|
||||
],
|
||||
|
||||
// MUST be logged in
|
||||
// MUST have 2fa
|
||||
// MUST be confirmed.
|
||||
// (this group includes the other Firefly III middleware)
|
||||
'user-full-auth' => [
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
Authenticate::class,
|
||||
MFAMiddleware::class,
|
||||
Range::class,
|
||||
Binder::class,
|
||||
InterestingMessage::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
// MUST be logged in
|
||||
// MUST have 2fa
|
||||
// MUST be confirmed.
|
||||
// MUST have owner role
|
||||
// (this group includes the other Firefly III middleware)
|
||||
'admin' => [
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartFireflySession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
Authenticate::class,
|
||||
// AuthenticateTwoFactor::class,
|
||||
IsAdmin::class,
|
||||
Range::class,
|
||||
Binder::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
|
||||
// full API authentication
|
||||
'api' => [AcceptHeaders::class, EnsureFrontendRequestsAreStateful::class, 'auth:api,sanctum', 'bindings'],
|
||||
// do only bindings, no auth
|
||||
'api_basic' => [AcceptHeaders::class, 'bindings'],
|
||||
];
|
||||
protected $middlewarePriority = [StartFireflySession::class, ShareErrorsFromSession::class, Authenticate::class, Binder::class, Authorize::class];
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class Binder
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function performBinding(string $key, string $value, Route $route)
|
||||
private function performBinding(string $key, object|string $value, Route $route)
|
||||
{
|
||||
$class = $this->binders[$key];
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\RequestedReportOnJournals;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupsRequestedReporting;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
@@ -145,7 +146,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
Log::debug('Now running report thing.');
|
||||
// will now send email to users.
|
||||
foreach ($result as $userId => $journals) {
|
||||
event(new RequestedReportOnJournals($userId, $journals));
|
||||
event(new TransactionGroupsRequestedReporting($userId, $journals));
|
||||
}
|
||||
|
||||
Log::debug('Done with handle()');
|
||||
@@ -383,7 +384,10 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
Log::info(sprintf('Created new transaction group #%d', $group->id));
|
||||
|
||||
// trigger event:
|
||||
event(new StoredTransactionGroup($group, $recurrence->apply_rules, true));
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
$flags->applyRules = $recurrence->apply_rules;
|
||||
event(new CreatedSingleTransactionGroup($group, $flags));
|
||||
// event(new StoredTransactionGroup($group, $recurrence->apply_rules, true));
|
||||
$this->groups->push($group);
|
||||
|
||||
// update recurring thing:
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AutomationHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* MailsNewTransactionsReport.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,34 +22,24 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\Model\TransactionGroup;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\RequestedReportOnJournals;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupsRequestedReporting;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Notifications\User\TransactionCreation;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
/**
|
||||
* Class AutomationHandler
|
||||
*/
|
||||
class AutomationHandler
|
||||
class MailsNewTransactionsReport implements ShouldQueue
|
||||
{
|
||||
/**
|
||||
* Respond to the creation of X journals.
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function reportJournals(RequestedReportOnJournals $event): void
|
||||
public function handle(TransactionGroupsRequestedReporting $event): void
|
||||
{
|
||||
Log::debug('In reportJournals.');
|
||||
Log::debug('In MailsNewTransactionsReport.');
|
||||
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ProcessesNewTransactionGroup.php
|
||||
* Copyright (c) 2026 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Listeners\Model\TransactionGroup;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
|
||||
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ProcessesNewTransactionGroup implements ShouldQueue
|
||||
{
|
||||
public function handle(CreatedSingleTransactionGroup $event): void
|
||||
{
|
||||
Log::debug(sprintf('In ProcessesNewTransactionGroup::handle(#%d)', $event->transactionGroup->id));
|
||||
if (true === $event->flags->batchSubmission) {
|
||||
Log::debug(sprintf('Will do nothing for group #%d because it is part of a batch.', $event->transactionGroup->id));
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Will join group #%d with all other open transaction groups and process them.', $event->transactionGroup->id));
|
||||
$collection = $event->transactionGroup->transactionJournals;
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$set = $collection->merge($repository->getUncompletedJournals());
|
||||
if (0 === $set->count()) {
|
||||
Log::debug('Set is empty, never mind.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (!$event->flags->applyRules) {
|
||||
Log::debug(sprintf('Will NOT process rules for %d journal(s)', $set->count()));
|
||||
}
|
||||
if (!$event->flags->recalculateCredit) {
|
||||
Log::debug(sprintf('Will NOT recalculate credit for %d journal(s)', $set->count()));
|
||||
}
|
||||
if (!$event->flags->fireWebhooks) {
|
||||
Log::debug(sprintf('Will NOT fire webhooks for %d journal(s)', $set->count()));
|
||||
}
|
||||
if ($event->flags->applyRules) {
|
||||
$this->processRules($set);
|
||||
}
|
||||
if ($event->flags->recalculateCredit) {
|
||||
$this->recalculateCredit($set);
|
||||
}
|
||||
if ($event->flags->fireWebhooks) {
|
||||
$this->fireWebhooks($set);
|
||||
}
|
||||
// always remove old statistics.
|
||||
$this->removePeriodStatistics($set);
|
||||
|
||||
// recalculate running balance if necessary.
|
||||
|
||||
Log::debug('Observe "created" of a transaction.');
|
||||
if (true === FireflyConfig::get('use_running_balance', config('firefly.feature_flags.running_balance_column'))->data) {
|
||||
$this->recalculateRunningBalance($set);
|
||||
}
|
||||
|
||||
$repository->markAsCompleted($set);
|
||||
}
|
||||
|
||||
private function recalculateRunningBalance(Collection $set): void
|
||||
{
|
||||
Log::debug('Now in recalculateRunningBalance');
|
||||
// find the earliest date in the set, based on date and _internal_previous_date
|
||||
$earliest = $set->pluck('date')->sort()->first();
|
||||
$entries = TransactionJournalMeta::whereIn('transaction_journal_id', $set->pluck('id')->toArray())->where('name', '_internal_previous_date')->get([
|
||||
'journal_meta.*',
|
||||
]);
|
||||
$array = $entries->toArray();
|
||||
if (count($array) > 0) {
|
||||
usort($array, function (array $a, array $b) {
|
||||
return Carbon::parse($a['data'])->gt(Carbon::parse($b['data']));
|
||||
});
|
||||
|
||||
/** @var Carbon $date */
|
||||
$date = Carbon::parse($array[0]['data']);
|
||||
$earliest = $date->lt($earliest) ? $date : $earliest;
|
||||
}
|
||||
|
||||
// get accounts
|
||||
$accounts = Account::leftJoin('transactions', 'transactions.account_id', 'accounts.id')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->leftJoin('account_types', 'account_types.id', 'accounts.account_type_id')
|
||||
->whereIn('transaction_journals.id', $set->pluck('id')->toArray())
|
||||
->get(['accounts.*'])
|
||||
;
|
||||
|
||||
AccountBalanceCalculator::optimizedCalculation($accounts, $earliest);
|
||||
}
|
||||
|
||||
private function removePeriodStatistics(Collection $set): void
|
||||
{
|
||||
Log::debug('Always remove period statistics');
|
||||
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
$repository->deleteStatisticsForCollection($set);
|
||||
}
|
||||
|
||||
private function fireWebhooks(Collection $set): void
|
||||
{
|
||||
// collect transaction groups by set ids.
|
||||
$groups = TransactionGroup::whereIn('id', array_unique($set->pluck('transaction_group_id')->toArray()))->get();
|
||||
|
||||
Log::debug(__METHOD__);
|
||||
$user = $set->first()->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
|
||||
// tell the generator which trigger it should look for
|
||||
$engine->setTrigger(WebhookTrigger::STORE_TRANSACTION);
|
||||
// tell the generator which objects to process
|
||||
$engine->setObjects($groups);
|
||||
// tell the generator to generate the messages
|
||||
$engine->generateMessages();
|
||||
|
||||
// trigger event to send them:
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
|
||||
private function recalculateCredit(Collection $set): void
|
||||
{
|
||||
Log::debug(sprintf('Will now recalculateCredit for %d journal(s)', $set->count()));
|
||||
|
||||
/** @var CreditRecalculateService $object */
|
||||
$object = app(CreditRecalculateService::class);
|
||||
$object->setJournals($set);
|
||||
$object->recalculate();
|
||||
}
|
||||
|
||||
private function processRules(Collection $set): void
|
||||
{
|
||||
Log::debug(sprintf('Will now processRules for %d journal(s)', $set->count()));
|
||||
$array = $set->pluck('id')->toArray();
|
||||
$journalIds = implode(',', $array);
|
||||
$user = $set->first()->user;
|
||||
Log::debug(sprintf('Add local operator for journal(s): %s', $journalIds));
|
||||
|
||||
// collect rules:
|
||||
$ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
|
||||
$ruleGroupRepository->setUser($user);
|
||||
|
||||
// add the groups to the rule engine.
|
||||
// it should run the rules in the group and cancel the group if necessary.
|
||||
Log::debug('Fire processRules with ALL store-journal rule groups.');
|
||||
$groups = $ruleGroupRepository->getRuleGroupsWithRules('store-journal');
|
||||
|
||||
// create and fire rule engine.
|
||||
$newRuleEngine = app(RuleEngineInterface::class);
|
||||
$newRuleEngine->setUser($user);
|
||||
$newRuleEngine->addOperator(['type' => 'journal_id', 'value' => $journalIds]);
|
||||
$newRuleEngine->setRuleGroups($groups);
|
||||
$newRuleEngine->fire();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* AuditEventHandler.php
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
* StoresAuditLogEntry.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,21 +22,17 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\Model\TransactionGroup;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupRequestsAuditLogEntry;
|
||||
use FireflyIII\Repositories\AuditLogEntry\ALERepositoryInterface;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AuditEventHandler
|
||||
*/
|
||||
class AuditEventHandler
|
||||
class StoresAuditLogEntry implements ShouldQueue
|
||||
{
|
||||
public function storeAuditEvent(TriggeredAuditLog $event): void
|
||||
public function handle(TransactionGroupRequestsAuditLogEntry $event): void
|
||||
{
|
||||
$array = [
|
||||
'auditable' => $event->auditable,
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* WebhookEventHandler.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
* SendsWebhookMessages.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,26 +22,20 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\Model\Webhook;
|
||||
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Jobs\SendWebhookMessage;
|
||||
use FireflyIII\Models\WebhookMessage;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class WebhookEventHandler
|
||||
*/
|
||||
class WebhookEventHandler
|
||||
class SendsWebhookMessages implements ShouldQueue
|
||||
{
|
||||
/**
|
||||
* Will try to send at most 3 messages so the flow doesn't get broken too much.
|
||||
*/
|
||||
public function sendWebhookMessages(): void
|
||||
public function handle(WebhookMessagesRequestSending $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s for %s', __METHOD__, get_class($event)));
|
||||
if (false === config('firefly.feature_flags.webhooks') || false === FireflyConfig::get('allow_webhooks', config('firefly.allow_webhooks'))->data) {
|
||||
Log::debug('Webhook event handler is disabled, do not run sendWebhookMessages().');
|
||||
|
||||
@@ -69,6 +65,6 @@ class WebhookEventHandler
|
||||
}
|
||||
|
||||
// clean up sent messages table:
|
||||
WebhookMessage::where('webhook_messages.sent', true)->where('webhook_messages.created_at', '<', now()->subDays(30))->delete();
|
||||
WebhookMessage::where('webhook_messages.sent', true)->where('webhook_messages.created_at', '<', now()->subDays(14))->delete();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* VersionCheckEventHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ChecksForNewVersion.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -19,40 +21,28 @@
|
||||
* 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\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\Security\System;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Deprecated;
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Events\Security\System\SystemRequestedVersionCheck;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class VersionCheckEventHandler
|
||||
*/
|
||||
class VersionCheckEventHandler
|
||||
class ChecksForNewVersion implements ShouldQueue
|
||||
{
|
||||
use UpdateTrait;
|
||||
|
||||
/**
|
||||
* Checks with GitHub to see if there is a new version.
|
||||
*
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws FireflyException
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
#[Deprecated(message: '?')]
|
||||
public function checkForUpdates(RequestedVersionCheckStatus $event): void
|
||||
public function handle(SystemRequestedVersionCheck $event): void
|
||||
{
|
||||
Log::debug('Now in checkForUpdates()');
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
// should not check for updates:
|
||||
$permission = FireflyConfig::get('permission_update_check', -1);
|
||||
@@ -96,7 +86,7 @@ class VersionCheckEventHandler
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
protected function warnToCheckForUpdates(RequestedVersionCheckStatus $event): void
|
||||
private function warnToCheckForUpdates(SystemRequestedVersionCheck $event): void
|
||||
{
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
@@ -38,10 +38,11 @@ use FireflyIII\Notifications\User\UserRegistration as UserRegistrationNotificati
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class HandlesNewUserRegistration
|
||||
class HandlesNewUserRegistration implements ShouldQueue
|
||||
{
|
||||
public function handle(NewUserRegistered $event): void
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AdminEventHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* NotifiesAboutNewInvitation.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -19,24 +21,47 @@
|
||||
* 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\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\Security\System;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Admin\InvitationCreated;
|
||||
use FireflyIII\Events\Security\System\NewInvitationCreated;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Mail\InvitationMail;
|
||||
use FireflyIII\Models\InvitedUser;
|
||||
use FireflyIII\Notifications\Admin\UserInvitation;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
/**
|
||||
* Class AdminEventHandler.
|
||||
*/
|
||||
class AdminEventHandler
|
||||
class NotifiesAboutNewInvitation implements ShouldQueue
|
||||
{
|
||||
public function sendInvitationNotification(InvitationCreated $event): void
|
||||
public function handle(NewInvitationCreated $event): void
|
||||
{
|
||||
$this->sendInvitationNotification($event->invitee);
|
||||
$this->sendRegistrationInvite($event->invitee);
|
||||
}
|
||||
|
||||
private function sendRegistrationInvite(InvitedUser $invitee): void
|
||||
{
|
||||
$email = $invitee->email;
|
||||
$admin = $invitee->user->email;
|
||||
$url = route('invite', [$invitee->invite_code]);
|
||||
|
||||
try {
|
||||
Mail::to($email)->send(new InvitationMail($invitee, $admin, $url));
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function sendInvitationNotification(InvitedUser $invitee): void
|
||||
{
|
||||
$sendMail = FireflyConfig::get('notification_invite_created', true)->data;
|
||||
if (false === $sendMail) {
|
||||
@@ -44,7 +69,7 @@ class AdminEventHandler
|
||||
}
|
||||
|
||||
try {
|
||||
Notification::send(new OwnerNotifiable(), new UserInvitation($event->invitee));
|
||||
Notification::send(new OwnerNotifiable(), new UserInvitation($invitee));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
@@ -61,6 +86,4 @@ class AdminEventHandler
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
|
||||
// Send new version message to admin.
|
||||
}
|
||||
@@ -29,10 +29,11 @@ use FireflyIII\Events\Security\System\SystemFoundNewVersionOnline;
|
||||
use FireflyIII\Notifications\Admin\VersionCheckResult;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesOwnerAboutNewVersion
|
||||
class NotifiesOwnerAboutNewVersion implements ShouldQueue
|
||||
{
|
||||
public function handle(SystemFoundNewVersionOnline $event): void
|
||||
{
|
||||
|
||||
@@ -28,10 +28,11 @@ use Exception;
|
||||
use FireflyIII\Events\Security\System\UnknownUserTriedLogin;
|
||||
use FireflyIII\Notifications\Admin\UnknownUserLoginAttempt;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesOwnerAboutUnknownUser
|
||||
class NotifiesOwnerAboutUnknownUser implements ShouldQueue
|
||||
{
|
||||
public function handle(UnknownUserTriedLogin $event): void
|
||||
{
|
||||
|
||||
@@ -30,10 +30,11 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Mail\ConfirmEmailChangeMail;
|
||||
use FireflyIII\Mail\UndoEmailChangeMail;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class HandlesChangeOfUserEmailAddress
|
||||
class HandlesChangeOfUserEmailAddress implements ShouldQueue
|
||||
{
|
||||
public function handle(UserChangedEmailAddress $event): void
|
||||
{
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasEnabledMFA;
|
||||
use FireflyIII\Notifications\Security\EnabledMFANotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutEnabledMFA
|
||||
class NotifiesUserAboutEnabledMFA implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasEnabledMFA $event): void
|
||||
{
|
||||
|
||||
@@ -26,10 +26,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserFailedLoginAttempt;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutFailedLogin
|
||||
class NotifiesUserAboutFailedLogin implements ShouldQueue
|
||||
{
|
||||
public function handle(UserFailedLoginAttempt $event): void
|
||||
{
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasFewMFABackupCodesLeft;
|
||||
use FireflyIII\Notifications\Security\MFABackupFewLeftNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutFewCodesLeft
|
||||
class NotifiesUserAboutFewCodesLeft implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasFewMFABackupCodesLeft $event): void
|
||||
{
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasGeneratedNewBackupCodes;
|
||||
use FireflyIII\Notifications\Security\NewBackupCodesNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutNewBackupCodes
|
||||
class NotifiesUserAboutNewBackupCodes implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasGeneratedNewBackupCodes $event): void
|
||||
{
|
||||
|
||||
@@ -28,10 +28,11 @@ use Exception;
|
||||
use FireflyIII\Events\Security\User\UserLoggedInFromNewIpAddress;
|
||||
use FireflyIII\Notifications\User\UserLogin;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutNewIpAddress
|
||||
class NotifiesUserAboutNewIpAddress implements ShouldQueue
|
||||
{
|
||||
public function handle(UserLoggedInFromNewIpAddress $event): void
|
||||
{
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasNoMFABackupCodesLeft;
|
||||
use FireflyIII\Notifications\Security\MFABackupNoLeftNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutNoCodesLeft
|
||||
class NotifiesUserAboutNoCodesLeft implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasNoMFABackupCodesLeft $event): void
|
||||
{
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserKeepsFailingMFA;
|
||||
use FireflyIII\Notifications\Security\MFAManyFailedAttemptsNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutRepeatedMFAFailures
|
||||
class NotifiesUserAboutRepeatedMFAFailures implements ShouldQueue
|
||||
{
|
||||
public function handle(UserKeepsFailingMFA $event): void
|
||||
{
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasUsedBackupCode;
|
||||
use FireflyIII\Notifications\Security\MFAUsedBackupCodeNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutUsedBackupCode
|
||||
class NotifiesUserAboutUsedBackupCode implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasUsedBackupCode $event): void
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* UserEventHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* RespondsToNewLogin.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -19,43 +21,40 @@
|
||||
* 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\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Admin\InvitationCreated;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Mail\InvitationMail;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Class UserEventHandler.
|
||||
*
|
||||
* This class responds to any events that have anything to do with the User object.
|
||||
*
|
||||
* The method name reflects what is being done. This is in the present tense.
|
||||
*/
|
||||
class UserEventHandler
|
||||
class RespondsToNewLogin implements ShouldQueue
|
||||
{
|
||||
public function handle(Login $event): void
|
||||
{
|
||||
$user = $event->user;
|
||||
if (!$user instanceof User) {
|
||||
throw new InvalidArgumentException(sprintf('User cannot be an instance of %s.', get_class($user)));
|
||||
}
|
||||
|
||||
$this->checkSingleUserIsAdmin($user);
|
||||
$this->demoUserBackToEnglish($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires to see if a user is admin.
|
||||
*/
|
||||
public function checkSingleUserIsAdmin(Login $event): void
|
||||
private function checkSingleUserIsAdmin(User $user): void
|
||||
{
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
|
||||
/** @var User $user */
|
||||
$user = $event->user;
|
||||
$count = $repository->count();
|
||||
|
||||
// only act when there is 1 user in the system and he has no admin rights.
|
||||
// only act when there is 1 user in the system, and he has no admin rights.
|
||||
if (1 === $count && !$repository->hasRole($user, 'owner')) {
|
||||
// user is the only user but does not have role "owner".
|
||||
$role = $repository->getRole('owner');
|
||||
@@ -74,13 +73,10 @@ class UserEventHandler
|
||||
/**
|
||||
* Set the demo user back to English.
|
||||
*/
|
||||
public function demoUserBackToEnglish(Login $event): void
|
||||
private function demoUserBackToEnglish(User $user): void
|
||||
{
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
|
||||
/** @var User $user */
|
||||
$user = $event->user;
|
||||
if ($repository->hasRole($user, 'demo')) {
|
||||
// set user back to English.
|
||||
Preferences::setForUser($user, 'language', 'en_US');
|
||||
@@ -89,23 +85,4 @@ class UserEventHandler
|
||||
Preferences::mark();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function sendRegistrationInvite(InvitationCreated $event): void
|
||||
{
|
||||
$invitee = $event->invitee->email;
|
||||
$admin = $event->invitee->user->email;
|
||||
$url = route('invite', [$event->invitee->invite_code]);
|
||||
|
||||
try {
|
||||
Mail::to($invitee)->send(new InvitationMail($invitee, $admin, $url));
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,11 @@ namespace FireflyIII\Listeners\Security\User;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserRequestedNewPassword;
|
||||
use FireflyIII\Notifications\User\UserNewPassword;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class SendsUserNewPassword
|
||||
class SendsUserNewPassword implements ShouldQueue
|
||||
{
|
||||
public function handle(UserRequestedNewPassword $event): void
|
||||
{
|
||||
|
||||
@@ -28,9 +28,10 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Events\Security\User\UserLoggedInFromNewIpAddress;
|
||||
use FireflyIII\Events\Security\User\UserSuccessfullyLoggedIn;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class StoresNewIpAddress
|
||||
class StoresNewIpAddress implements ShouldQueue
|
||||
{
|
||||
public function handle(UserSuccessfullyLoggedIn $event): void
|
||||
{
|
||||
|
||||
@@ -60,8 +60,11 @@ class Account extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$accountId = (int) $value;
|
||||
|
||||
|
||||
@@ -62,8 +62,11 @@ class Attachment extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$attachmentId = (int) $value;
|
||||
|
||||
|
||||
@@ -59,8 +59,11 @@ class AvailableBudget extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$availableBudgetId = (int) $value;
|
||||
|
||||
|
||||
@@ -74,8 +74,11 @@ class Bill extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$billId = (int) $value;
|
||||
|
||||
|
||||
@@ -53,8 +53,11 @@ class Budget extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$budgetId = (int) $value;
|
||||
|
||||
|
||||
@@ -53,8 +53,11 @@ class BudgetLimit extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$budgetLimitId = (int) $value;
|
||||
$budgetLimit = self::where('budget_limits.id', $budgetLimitId)
|
||||
|
||||
@@ -52,8 +52,11 @@ class Category extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$categoryId = (int) $value;
|
||||
|
||||
|
||||
@@ -42,8 +42,11 @@ class InvitedUser extends Model
|
||||
/**
|
||||
* Route binder. Converts the key in the URL to the specified object (or throw 404).
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$attemptId = (int) $value;
|
||||
|
||||
|
||||
@@ -41,8 +41,11 @@ class LinkType extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$linkTypeId = (int) $value;
|
||||
$linkType = self::find($linkTypeId);
|
||||
|
||||
@@ -45,8 +45,11 @@ class ObjectGroup extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$objectGroupId = (int) $value;
|
||||
|
||||
|
||||
@@ -60,8 +60,11 @@ class PiggyBank extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$piggyBankId = (int) $value;
|
||||
$piggyBank = self::where('piggy_banks.id', $piggyBankId)
|
||||
|
||||
@@ -42,8 +42,11 @@ class Preference extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
@@ -74,8 +74,11 @@ class Recurrence extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$recurrenceId = (int) $value;
|
||||
|
||||
|
||||
@@ -52,8 +52,11 @@ class Rule extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$ruleId = (int) $value;
|
||||
|
||||
|
||||
@@ -54,8 +54,11 @@ class RuleGroup extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$ruleGroupId = (int) $value;
|
||||
|
||||
|
||||
@@ -52,8 +52,11 @@ class Tag extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$tagId = (int) $value;
|
||||
|
||||
|
||||
@@ -48,8 +48,11 @@ class TransactionCurrency extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$currencyId = (int) $value;
|
||||
$currency = self::find($currencyId);
|
||||
|
||||
@@ -55,8 +55,11 @@ class TransactionGroup extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
Log::debug(sprintf('Now in %s("%s")', __METHOD__, $value));
|
||||
if (auth()->check()) {
|
||||
$groupId = (int) $value;
|
||||
|
||||
@@ -79,8 +79,11 @@ class TransactionJournal extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
if (auth()->check()) {
|
||||
$journalId = (int) $value;
|
||||
|
||||
|
||||
@@ -41,8 +41,12 @@ class TransactionJournalLink extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
|
||||
if (auth()->check()) {
|
||||
$linkId = (int) $value;
|
||||
$link = self::where('journal_links.id', $linkId)
|
||||
|
||||
@@ -72,12 +72,15 @@ class TransactionType extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $type): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if (!auth()->check()) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$transactionType = self::where('type', ucfirst($type))->first();
|
||||
if ($value instanceof self) {
|
||||
$value = (string) $value->type;
|
||||
}
|
||||
$transactionType = self::where('type', ucfirst($value))->first();
|
||||
if (null !== $transactionType) {
|
||||
return $transactionType;
|
||||
}
|
||||
|
||||
@@ -44,9 +44,13 @@ class UserGroup extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if (auth()->check()) {
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
|
||||
$userGroupId = (int) $value;
|
||||
|
||||
/** @var User $user */
|
||||
|
||||
@@ -130,9 +130,12 @@ class Webhook extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if (auth()->check()) {
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
$webhookId = (int) $value;
|
||||
|
||||
/** @var User $user */
|
||||
|
||||
@@ -42,9 +42,12 @@ class WebhookAttempt extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if (auth()->check()) {
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
$attemptId = (int) $value;
|
||||
|
||||
/** @var User $user */
|
||||
|
||||
@@ -44,9 +44,12 @@ class WebhookMessage extends Model
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function routeBinder(string $value): self
|
||||
public static function routeBinder(self|string $value): self
|
||||
{
|
||||
if (auth()->check()) {
|
||||
if ($value instanceof self) {
|
||||
$value = (int) $value->id;
|
||||
}
|
||||
$messageId = (int) $value;
|
||||
|
||||
/** @var User $user */
|
||||
|
||||
@@ -58,7 +58,7 @@ class SubscriptionsOverdueReminder extends Notification
|
||||
$info = [];
|
||||
$count = 0;
|
||||
foreach ($this->overdue as $item) {
|
||||
$current = ['bill' => $item['bill']];
|
||||
$current = ['bill' => $item['bill']];
|
||||
$current['pay_dates'] = array_map(static fn (string $date): string => new Carbon($date)->isoFormat((string) trans(
|
||||
'config.month_and_day_moment_js'
|
||||
)), $item['dates']['pay_dates']);
|
||||
|
||||
@@ -23,19 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Providers;
|
||||
|
||||
use FireflyIII\Events\Admin\InvitationCreated;
|
||||
use FireflyIII\Events\DestroyedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TriggeredStoredTransactionGroup;
|
||||
use FireflyIII\Events\Preferences\UserGroupChangedPrimaryCurrency;
|
||||
use FireflyIII\Events\RequestedReportOnJournals;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Events\StoredAccount;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Events\UpdatedAccount;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Laravel\Passport\Events\AccessTokenCreated;
|
||||
use Override;
|
||||
@@ -48,96 +41,19 @@ use Override;
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
protected $listen = [
|
||||
// is a User related event.
|
||||
// RegisteredUser::class => [
|
||||
// 'FireflyIII\Handlers\Events\UserEventHandler@createExchangeRates',
|
||||
// ],
|
||||
// UserAttemptedLogin::class => [
|
||||
// 'FireflyIII\Handlers\Events\UserEventHandler@sendLoginAttemptNotification',
|
||||
// ],
|
||||
// is a User related event.
|
||||
Login::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@demoUserBackToEnglish',
|
||||
],
|
||||
// DetectedNewIPAddress::class => [
|
||||
// 'FireflyIII\Handlers\Events\UserEventHandler@notifyNewIPAddress',
|
||||
// ],
|
||||
RequestedVersionCheckStatus::class => ['FireflyIII\Handlers\Events\VersionCheckEventHandler@checkForUpdates'],
|
||||
RequestedReportOnJournals::class => ['FireflyIII\Handlers\Events\AutomationHandler@reportJournals'],
|
||||
|
||||
// is a User related event.
|
||||
InvitationCreated::class => [
|
||||
'FireflyIII\Handlers\Events\AdminEventHandler@sendInvitationNotification',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationInvite',
|
||||
],
|
||||
|
||||
// is a Transaction Journal related event.
|
||||
StoredTransactionGroup::class => ['FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers'],
|
||||
TriggeredStoredTransactionGroup::class => ['FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerRulesManually'],
|
||||
// StoredTransactionGroup::class => ['FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers'],
|
||||
// TriggeredStoredTransactionGroup::class => ['FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerRulesManually'],
|
||||
// is a Transaction Journal related event.
|
||||
UpdatedTransactionGroup::class => ['FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers'],
|
||||
DestroyedTransactionGroup::class => ['FireflyIII\Handlers\Events\DestroyedGroupEventHandler@runAllHandlers'],
|
||||
// UpdatedTransactionGroup::class => ['FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers'],
|
||||
// DestroyedTransactionGroup::class => ['FireflyIII\Handlers\Events\DestroyedGroupEventHandler@runAllHandlers'],
|
||||
// API related events:
|
||||
AccessTokenCreated::class => ['FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated'],
|
||||
|
||||
// Webhook related event:
|
||||
RequestedSendWebhookMessages::class => ['FireflyIII\Handlers\Events\WebhookEventHandler@sendWebhookMessages'],
|
||||
|
||||
// AccessTokenCreated::class => ['FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated'],
|
||||
// account related events:
|
||||
StoredAccount::class => ['FireflyIII\Handlers\Events\StoredAccountEventHandler@recalculateCredit'],
|
||||
UpdatedAccount::class => ['FireflyIII\Handlers\Events\UpdatedAccountEventHandler@recalculateCredit'],
|
||||
|
||||
// subscription related events:
|
||||
// SubscriptionNeedsExtensionOrRenewal::class => [
|
||||
// 'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill',
|
||||
// ],
|
||||
// WarnUserAboutOverdueSubscriptions::class => [
|
||||
// 'FireflyIII\Handlers\Events\BillEventHandler@warnAboutOverdueSubscriptions',
|
||||
// ],
|
||||
|
||||
// audit log events:
|
||||
TriggeredAuditLog::class => ['FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent'],
|
||||
// piggy bank related events:
|
||||
// PiggyBankAmountIsChanged::class => [
|
||||
// 'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount',
|
||||
// ],
|
||||
// ChangedName::class => [
|
||||
// 'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changedPiggyBankName',
|
||||
// ],
|
||||
|
||||
// rule actions
|
||||
// RuleActionFailedOnArray::class => [
|
||||
// 'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray',
|
||||
// ],
|
||||
// RuleActionFailedOnObject::class => [
|
||||
// 'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject',
|
||||
// ],
|
||||
|
||||
// security related
|
||||
// EnabledMFA::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAEnabledMail',
|
||||
// ],
|
||||
// DisabledMFA::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFADisabledMail',
|
||||
// ],
|
||||
// MFANewBackupCodes::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendNewMFABackupCodesMail',
|
||||
// ],
|
||||
// MFAUsedBackupCode::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendUsedBackupCodeMail',
|
||||
// ],
|
||||
// MFABackupFewLeft::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail',
|
||||
// ],
|
||||
// MFABackupNoLeft::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail',
|
||||
// ],
|
||||
// MFAManyFailedAttempts::class => [
|
||||
// 'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail',
|
||||
// ],
|
||||
// StoredAccount::class => ['FireflyIII\Handlers\Events\StoredAccountEventHandler@recalculateCredit'],
|
||||
// UpdatedAccount::class => ['FireflyIII\Handlers\Events\UpdatedAccountEventHandler@recalculateCredit'],
|
||||
// preferences
|
||||
UserGroupChangedPrimaryCurrency::class => ['FireflyIII\Handlers\Events\PreferencesEventHandler@resetPrimaryCurrencyAmounts'],
|
||||
// UserGroupChangedPrimaryCurrency::class => ['FireflyIII\Handlers\Events\PreferencesEventHandler@resetPrimaryCurrencyAmounts'],
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,7 @@ use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Support\Collection;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Class JournalRepository.
|
||||
@@ -250,4 +251,20 @@ class JournalRepository implements JournalRepositoryInterface, UserGroupInterfac
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getUncompletedJournals(): Collection
|
||||
{
|
||||
return $this->userGroup
|
||||
->transactionJournals()
|
||||
->where('completed', false)
|
||||
->get(['transaction_journals.*'])
|
||||
;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function markAsCompleted(Collection $set): void
|
||||
{
|
||||
TransactionJournal::whereIn('id', $set->pluck('id')->toArray())->update(['completed' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function destroyGroup(TransactionGroup $transactionGroup): void;
|
||||
|
||||
public function getUncompletedJournals(): Collection;
|
||||
|
||||
public function markAsCompleted(Collection $set): void;
|
||||
|
||||
/**
|
||||
* Deletes a journal.
|
||||
*/
|
||||
|
||||
@@ -25,12 +25,18 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\PeriodStatistic;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\PeriodStatistic;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
@@ -137,8 +143,98 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface, U
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function deleteStatisticsForPrefix(UserGroup $userGroup, string $prefix, Carbon $date): void
|
||||
public function deleteStatisticsForPrefix(string $prefix, Collection $dates): void
|
||||
{
|
||||
$userGroup->periodStatistics()->where('start', '<=', $date)->where('end', '>=', $date)->where('type', 'LIKE', sprintf('%s%%', $prefix))->delete();
|
||||
$count = $this->userGroup
|
||||
->periodStatistics()
|
||||
->where(function (Builder $q) use ($dates): void {
|
||||
foreach ($dates as $date) {
|
||||
$q->where(function (Builder $q1) use ($date): void {
|
||||
$q1->where('start', '<=', $date)->where('end', '>=', $date);
|
||||
});
|
||||
}
|
||||
})
|
||||
->where('type', 'LIKE', sprintf('%s%%', $prefix))
|
||||
->delete()
|
||||
;
|
||||
Log::debug(sprintf('Deleted %d entries for prefix "%s"', $count, $prefix));
|
||||
}
|
||||
|
||||
public function deleteStatisticsForType(string $class, Collection $objects, Collection $dates): void
|
||||
{
|
||||
if (0 === count($objects)) {
|
||||
Log::debug(sprintf('Nothing to delete in deleteStatisticsForType("%s")', $class));
|
||||
|
||||
return;
|
||||
}
|
||||
$count = PeriodStatistic::where('primary_statable_type', $class)
|
||||
->whereIn('primary_statable_id', $objects->pluck('id')->toArray())
|
||||
->where(function (Builder $q) use ($dates): void {
|
||||
foreach ($dates as $date) {
|
||||
$q->where(function (Builder $q1) use ($date): void {
|
||||
$q1->where('start', '<=', $date)->where('end', '>=', $date);
|
||||
});
|
||||
}
|
||||
})
|
||||
->delete()
|
||||
;
|
||||
Log::debug(sprintf('Delete %d statistics for %dx %s', $count, $objects->count(), $class));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function deleteStatisticsForCollection(Collection $set): void
|
||||
{
|
||||
Log::debug(sprintf('Delete statistics for %d transaction journals.', count($set)));
|
||||
// collect all transactions:
|
||||
$transactions = Transaction::whereIn('transaction_journal_id', $set->pluck('id')->toArray())->get(['transactions.*']);
|
||||
|
||||
// collect all accounts and delete stats:
|
||||
$accounts = Account::whereIn('id', $transactions->pluck('account_id')->toArray())->get(['accounts.*']);
|
||||
$dates = $set->pluck('date');
|
||||
$this->deleteStatisticsForType(Account::class, $accounts, $dates);
|
||||
|
||||
// collect all categories, and remove stats.
|
||||
$categories = Category::whereIn(
|
||||
'id',
|
||||
DB::table('category_transaction_journal')
|
||||
->whereIn('transaction_journal_id', $set->pluck('id')->toArray())
|
||||
->get(['category_transaction_journal.category_id'])
|
||||
->pluck('category_id')
|
||||
->toArray()
|
||||
)->get(['categories.*']);
|
||||
$this->deleteStatisticsForType(Category::class, $categories, $dates);
|
||||
|
||||
// budgets, same thing
|
||||
$budgets = Budget::whereIn(
|
||||
'id',
|
||||
DB::table('budget_transaction_journal')
|
||||
->whereIn('transaction_journal_id', $set->pluck('id')->toArray())
|
||||
->get(['budget_transaction_journal.budget_id'])
|
||||
->pluck('budget_id')
|
||||
->toArray()
|
||||
)->get(['budgets.*']);
|
||||
$this->deleteStatisticsForType(Budget::class, $budgets, $dates);
|
||||
|
||||
// tags
|
||||
$tags = Tag::whereIn(
|
||||
'id',
|
||||
DB::table('tag_transaction_journal')
|
||||
->whereIn('transaction_journal_id', $set->pluck('id')->toArray())
|
||||
->get(['tag_transaction_journal.tag_id'])
|
||||
->pluck('tag_id')
|
||||
->toArray()
|
||||
)->get(['tags.*']);
|
||||
$this->deleteStatisticsForType(Tag::class, $tags, $dates);
|
||||
|
||||
// remove for no tag, no cat, etc.
|
||||
if (0 === $categories->count()) {
|
||||
$this->deleteStatisticsForPrefix('no_category', $dates);
|
||||
}
|
||||
if (0 === $budgets->count()) {
|
||||
$this->deleteStatisticsForPrefix('no_budget', $dates);
|
||||
}
|
||||
if (0 === $tags->count()) {
|
||||
$this->deleteStatisticsForPrefix('no_tag', $dates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,13 @@ namespace FireflyIII\Repositories\PeriodStatistic;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\PeriodStatistic;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface PeriodStatisticRepositoryInterface
|
||||
{
|
||||
public function deleteStatisticsForCollection(Collection $set);
|
||||
|
||||
public function findPeriodStatistics(Model $model, Carbon $start, Carbon $end, array $types): Collection;
|
||||
|
||||
public function findPeriodStatistic(Model $model, Carbon $start, Carbon $end, string $type): Collection;
|
||||
@@ -54,5 +55,5 @@ interface PeriodStatisticRepositoryInterface
|
||||
|
||||
public function deleteStatisticsForModel(Model $model, Carbon $date): void;
|
||||
|
||||
public function deleteStatisticsForPrefix(UserGroup $userGroup, string $prefix, Carbon $date): void;
|
||||
public function deleteStatisticsForPrefix(string $prefix, Collection $dates): void;
|
||||
}
|
||||
|
||||
@@ -172,7 +172,11 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
}
|
||||
$listedJournals[] = $journalId;
|
||||
|
||||
$array[$currencyId]['tags'][$tagId] ??= ['id' => $tagId, 'name' => $tagName, 'transaction_journals' => []];
|
||||
$array[$currencyId]['tags'][$tagId] ??= [
|
||||
'id' => $tagId,
|
||||
'name' => $tagName,
|
||||
'transaction_journals' => [],
|
||||
];
|
||||
$journalId = (int) $journal['transaction_journal_id'];
|
||||
$array[$currencyId]['tags'][$tagId]['transaction_journals'][$journalId] = [
|
||||
'amount' => Steam::positive($journal['amount']),
|
||||
|
||||
@@ -34,6 +34,7 @@ use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -43,9 +44,15 @@ class CreditRecalculateService
|
||||
{
|
||||
private ?Account $account = null;
|
||||
private ?TransactionGroup $group = null;
|
||||
private Collection $journals;
|
||||
private AccountRepositoryInterface $repository;
|
||||
private array $work = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->journals = new Collection();
|
||||
}
|
||||
|
||||
public function recalculate(): void
|
||||
{
|
||||
if (true !== config('firefly.feature_flags.handle_debts')) {
|
||||
@@ -58,25 +65,46 @@ class CreditRecalculateService
|
||||
// work based on account.
|
||||
$this->processAccount();
|
||||
}
|
||||
if ($this->journals->count() > 0) {
|
||||
$this->processJournals();
|
||||
}
|
||||
if (0 === count($this->work)) {
|
||||
Log::debug('No work found for recalculate() to do.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->processWork();
|
||||
}
|
||||
|
||||
private function processGroup(): void
|
||||
private function collectFromJournals(Collection $transactionJournals): void
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($this->group->transactionJournals as $journal) {
|
||||
try {
|
||||
$this->findByJournal($journal);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getTraceAsString());
|
||||
Log::error(sprintf('Could not find work account for transaction group #%d.', $this->group->id));
|
||||
Log::debug('Now in collectFromJournals()');
|
||||
$valid = config('firefly.valid_liabilities');
|
||||
$accounts = Account::leftJoin('transactions', 'transactions.account_id', 'accounts.id')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->leftJoin('account_types', 'account_types.id', 'accounts.account_type_id')
|
||||
->whereIn('transaction_journals.id', $transactionJournals->pluck('id')->toArray())
|
||||
->whereIn('account_types.type', $valid)
|
||||
->get(['accounts.*'])
|
||||
;
|
||||
if ($accounts->count() > 0) {
|
||||
Log::debug(sprintf('Found %d account(s) to process.', $accounts->count()));
|
||||
foreach ($accounts as $account) {
|
||||
$this->work[] = $account;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function processGroup(): void
|
||||
{
|
||||
$this->collectFromJournals($this->group->transactionJournals);
|
||||
}
|
||||
|
||||
private function processJournals(): void
|
||||
{
|
||||
$this->collectFromJournals($this->journals);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@@ -460,4 +488,9 @@ class CreditRecalculateService
|
||||
{
|
||||
$this->group = $group;
|
||||
}
|
||||
|
||||
public function setJournals(Collection $journals): void
|
||||
{
|
||||
$this->journals = $journals;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Safe\Exceptions\JsonException;
|
||||
|
||||
@@ -378,7 +377,7 @@ trait JournalServiceTrait
|
||||
return $amount;
|
||||
}
|
||||
|
||||
protected function storeBudget(TransactionJournal $journal, NullArrayObject $data): void
|
||||
protected function storeBudget(TransactionJournal $journal, array $data): void
|
||||
{
|
||||
if (TransactionTypeEnum::WITHDRAWAL->value !== $journal->transactionType->type) {
|
||||
$journal->budgets()->sync([]);
|
||||
@@ -396,7 +395,7 @@ trait JournalServiceTrait
|
||||
$journal->budgets()->sync([]);
|
||||
}
|
||||
|
||||
protected function storeCategory(TransactionJournal $journal, NullArrayObject $data): void
|
||||
protected function storeCategory(TransactionJournal $journal, array $data): void
|
||||
{
|
||||
$category = $this->categoryRepository->findCategory($data['category_id'], $data['category_name']);
|
||||
if (null !== $category) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user