mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-03-21 20:47:05 +00:00
Compare commits
32 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7888023c1a | ||
|
|
3032118788 | ||
|
|
89d96ddc17 | ||
|
|
97c9937571 | ||
|
|
c46aca0594 | ||
|
|
0b33e1ff09 | ||
|
|
d267d2a0b0 | ||
|
|
f2996dcebe | ||
|
|
ebb6a186cc | ||
|
|
304fae439a | ||
|
|
9ca81cf305 | ||
|
|
cad5fb6d6b | ||
|
|
53efafdbb2 | ||
|
|
7922017288 | ||
|
|
4e910a33dd | ||
|
|
bb031cdeb6 | ||
|
|
60026bbcba | ||
|
|
e96a1850da | ||
|
|
bd2a746b8a | ||
|
|
e4a3cbc9da | ||
|
|
18734b0edd | ||
|
|
f52b3bf5f5 | ||
|
|
3abba71f8d | ||
|
|
95bdc87ed7 | ||
|
|
9a66b4017b | ||
|
|
610e3f3ae5 | ||
|
|
a58e70c08b | ||
|
|
24c96d40c9 | ||
|
|
ae680cd41f | ||
|
|
5e9ea1ca10 | ||
|
|
6f558f424d | ||
|
|
4387876203 |
@@ -63,30 +63,28 @@ class TriggerController extends Controller
|
||||
{
|
||||
// find recurrence occurrence for this date and trigger it.
|
||||
// grab the date from the last time the recurrence fired:
|
||||
$backupDate = $recurrence->latest_date;
|
||||
$date = $request->getDate();
|
||||
$backupDate = $recurrence->latest_date;
|
||||
$date = $request->getDate();
|
||||
|
||||
// fire the recurring cron job on the given date, then post-date the created transaction.
|
||||
Log::info(sprintf('Trigger: will now fire recurring cron job task for date "%s".', $date->format('Y-m-d H:i:s')));
|
||||
|
||||
/** @var CreateRecurringTransactions $job */
|
||||
$job = app(CreateRecurringTransactions::class);
|
||||
$job = app(CreateRecurringTransactions::class);
|
||||
$job->setRecurrences(new Collection()->push($recurrence));
|
||||
$job->setDate($date);
|
||||
$job->setForce(false);
|
||||
$job->handle();
|
||||
Log::debug('Done with recurrence.');
|
||||
|
||||
$groups = $job->getGroups();
|
||||
$groups = $job->getGroups();
|
||||
$this->repository->markGroupsAsNow($groups);
|
||||
$recurrence->latest_date = $backupDate;
|
||||
$recurrence->latest_date_tz = $backupDate?->format('e');
|
||||
$recurrence->save();
|
||||
$recurrence = $this->repository->setLatestDate($recurrence, $backupDate);
|
||||
Preferences::mark();
|
||||
|
||||
// enrich groups and return them:
|
||||
|
||||
$paginator = new LengthAwarePaginator(new Collection(), 0, 1);
|
||||
$paginator = new LengthAwarePaginator(new Collection(), 0, 1);
|
||||
if ($groups->count() > 0) {
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
@@ -98,20 +96,20 @@ class TriggerController extends Controller
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
}
|
||||
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
$paginator->setPath(route('api.v1.recurrences.trigger', [$recurrence->id]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
$admin = auth()->user();
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$admin = auth()->user();
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$transactions = $enrichment->enrich($paginator->getCollection());
|
||||
$transactions = $enrichment->enrich($paginator->getCollection());
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace FireflyIII\Api\V1\Controllers\Models\Transaction;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Transaction\UpdateRequest;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||
@@ -72,27 +73,29 @@ class UpdateController extends Controller
|
||||
public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse
|
||||
{
|
||||
Log::debug('Now in update routine for transaction group');
|
||||
$data = $request->getAll();
|
||||
$oldHash = $this->groupRepository->getCompareHash($transactionGroup);
|
||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||
$newHash = $this->groupRepository->getCompareHash($transactionGroup);
|
||||
$manager = $this->getManager();
|
||||
$data = $request->getAll();
|
||||
$oldHash = $this->groupRepository->getCompareHash($transactionGroup);
|
||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||
$newHash = $this->groupRepository->getCompareHash($transactionGroup);
|
||||
$manager = $this->getManager();
|
||||
|
||||
Preferences::mark();
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
$runRecalculations = $oldHash !== $newHash;
|
||||
$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));
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
$flags->applyRules = $applyRules;
|
||||
$flags->fireWebhooks = $fireWebhooks;
|
||||
$flags->recalculateCredit = $runRecalculations;
|
||||
event(new UpdatedSingleTransactionGroup($transactionGroup, $flags));
|
||||
|
||||
/** @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)
|
||||
// filter on transaction group.
|
||||
@@ -101,20 +104,20 @@ class UpdateController extends Controller
|
||||
->withAPIInformation()
|
||||
;
|
||||
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
if (null === $selectedGroup) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers\System;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UserRequestedBatchProcessing;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -45,6 +44,7 @@ class BatchController extends Controller
|
||||
parent::__construct();
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->repository = app(JournalRepositoryInterface::class);
|
||||
$this->repository->setUser(auth()->user()); // should not have to do this.
|
||||
|
||||
return $next($request);
|
||||
});
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
@@ -89,24 +90,24 @@ class StoreRequest extends FormRequest
|
||||
if (0 !== count($validator->failed())) {
|
||||
return;
|
||||
}
|
||||
$data = $validator->getData();
|
||||
$data = $validator->getData();
|
||||
|
||||
// if no currency has been provided, use the user's default currency:
|
||||
/** @var TransactionCurrencyFactory $factory */
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
|
||||
if (null === $currency) {
|
||||
$currency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
$currency->enabled = true;
|
||||
$currency->save();
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$repository->enable($currency);
|
||||
|
||||
// validator already concluded start and end are valid dates:
|
||||
$start = Carbon::parse($data['start'], config('app.timezone'));
|
||||
$end = Carbon::parse($data['end'], config('app.timezone'));
|
||||
$start = Carbon::parse($data['start'], config('app.timezone'));
|
||||
$end = Carbon::parse($data['end'], config('app.timezone'));
|
||||
|
||||
// find limit with same date range and currency.
|
||||
$limit = $budget
|
||||
$limit = $budget
|
||||
->budgetlimits()
|
||||
->where('budget_limits.start_date', $start->format('Y-m-d'))
|
||||
->where('budget_limits.end_date', $end->format('Y-m-d'))
|
||||
|
||||
@@ -38,6 +38,8 @@ use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Destroy\GenericDestroyService;
|
||||
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -51,9 +53,13 @@ class CorrectsAmounts extends Command
|
||||
|
||||
protected $description = 'This command makes sure positive and negative amounts are recorded correctly.';
|
||||
protected $signature = 'correction:amounts';
|
||||
private JournalDestroyService $service;
|
||||
private GenericDestroyService $genericService;
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$this->service = new JournalDestroyService();
|
||||
$this->genericService = new GenericDestroyService();
|
||||
// transfers must not have foreign currency info if both accounts have the same currency.
|
||||
$this->correctTransfers();
|
||||
// auto budgets must be positive
|
||||
@@ -177,8 +183,7 @@ class CorrectsAmounts extends Command
|
||||
|
||||
private function deleteJournal(TransactionJournal $journal): void
|
||||
{
|
||||
$journal->transactionGroup?->delete();
|
||||
$journal->delete();
|
||||
$this->service->destroy($journal);
|
||||
}
|
||||
|
||||
private function fixAutoBudgets(): void
|
||||
@@ -282,7 +287,7 @@ class CorrectsAmounts extends Command
|
||||
));
|
||||
$item->rule->active = false;
|
||||
$item->rule->save();
|
||||
$item->forceDelete();
|
||||
$this->genericService->deleteRuleTrigger($item);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Handlers\Events\UpdatedGroupEventHandler;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -44,8 +44,8 @@ class CorrectsGroupAccounts extends Command
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$groups = [];
|
||||
$res = TransactionJournal::groupBy('transaction_group_id')->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
|
||||
$groups = [];
|
||||
$res = TransactionJournal::groupBy('transaction_group_id')->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($res as $journal) {
|
||||
@@ -53,13 +53,13 @@ class CorrectsGroupAccounts extends Command
|
||||
$groups[] = (int) $journal->transaction_group_id;
|
||||
}
|
||||
}
|
||||
$handler = new UpdatedGroupEventHandler();
|
||||
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);
|
||||
$group = TransactionGroup::find($groupId);
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
$flags->applyRules = true;
|
||||
$flags->fireWebhooks = true;
|
||||
$flags->recalculateCredit = true;
|
||||
event(new UpdatedSingleTransactionGroup($group, $flags));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -25,28 +25,9 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Handlers\Observer\TransactionObserver;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Services\Internal\Recalculate\PrimaryAmountRecalculationService;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder as DatabaseBuilder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CorrectsPrimaryCurrencyAmounts extends Command
|
||||
@@ -70,186 +51,11 @@ class CorrectsPrimaryCurrencyAmounts extends Command
|
||||
Log::debug('Will update all primary currency amounts. This may take some time.');
|
||||
$this->friendlyWarning('Recalculating primary currency amounts for all objects. This may take some time!');
|
||||
|
||||
/** @var UserGroupRepositoryInterface $repository */
|
||||
$repository = app(UserGroupRepositoryInterface::class);
|
||||
$calculator = new PrimaryAmountRecalculationService();
|
||||
$calculator->recalculate();
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
/** @var UserGroup $userGroup */
|
||||
foreach ($repository->getAll() as $userGroup) {
|
||||
$this->recalculateForGroup($userGroup);
|
||||
}
|
||||
$this->friendlyInfo('Recalculated all primary currency amounts.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function recalculateForGroup(UserGroup $userGroup): void
|
||||
{
|
||||
Log::debug(sprintf('Now recalculating for user group #%d', $userGroup->id));
|
||||
$this->recalculateAccounts($userGroup);
|
||||
|
||||
// do a check with the group's currency so we can skip some stuff.
|
||||
$currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
|
||||
|
||||
$this->recalculatePiggyBanks($userGroup, $currency);
|
||||
$this->recalculateBudgets($userGroup, $currency);
|
||||
$this->recalculateAvailableBudgets($userGroup, $currency);
|
||||
$this->recalculateBills($userGroup, $currency);
|
||||
$this->calculateTransactions($userGroup, $currency);
|
||||
}
|
||||
|
||||
private function recalculateAccounts(UserGroup $userGroup): void
|
||||
{
|
||||
$set = $userGroup
|
||||
->accounts()
|
||||
->where(static function (EloquentBuilder $q): void {
|
||||
$q->whereNotNull('virtual_balance');
|
||||
|
||||
// this needs a different piece of code for postgres.
|
||||
if ('pgsql' === config('database.default')) {
|
||||
$q->orWhere(DB::raw('CAST(virtual_balance AS TEXT)'), '!=', '');
|
||||
}
|
||||
if ('pgsql' !== config('database.default')) {
|
||||
$q->orWhere('virtual_balance', '!=', '');
|
||||
}
|
||||
})
|
||||
->get()
|
||||
;
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($set as $account) {
|
||||
$account->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d accounts for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
private function recalculatePiggyBanks(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getPiggyBanks();
|
||||
$set = $set->filter(static fn (PiggyBank $piggyBank): bool => $currency->id !== $piggyBank->transaction_currency_id);
|
||||
foreach ($set as $piggyBank) {
|
||||
$piggyBank->encrypted = false;
|
||||
$piggyBank->save();
|
||||
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
$account->pivot->native_current_amount = null;
|
||||
if (0 !== bccomp((string) $account->pivot->current_amount, '0')) {
|
||||
$account->pivot->native_current_amount = $converter->convert(
|
||||
$piggyBank->transactionCurrency,
|
||||
$currency,
|
||||
today(),
|
||||
(string) $account->pivot->current_amount
|
||||
);
|
||||
}
|
||||
$account->pivot->save();
|
||||
}
|
||||
$this->recalculatePiggyBankEvents($piggyBank);
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d piggy banks for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
private function recalculatePiggyBankEvents(PiggyBank $piggyBank): void
|
||||
{
|
||||
$set = $piggyBank->piggyBankEvents()->get();
|
||||
$set->each(static function (PiggyBankEvent $event): void { // @phpstan-ignore-line
|
||||
$event->touch();
|
||||
});
|
||||
Log::debug(sprintf('Recalculated %d piggy bank events.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateBudgets(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $userGroup->budgets()->get();
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$this->recalculateBudgetLimits($budget, $currency);
|
||||
$this->recalculateAutoBudgets($budget, $currency);
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d budgets.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateBudgetLimits(Budget $budget, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $budget->budgetlimits()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($set as $limit) {
|
||||
Log::debug(sprintf('Will now touch BL #%d', $limit->id));
|
||||
$limit->touch();
|
||||
Log::debug(sprintf('Done with touch BL #%d', $limit->id));
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d budget limits for budget #%d.', $set->count(), $budget->id));
|
||||
}
|
||||
|
||||
private function recalculateAutoBudgets(Budget $budget, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $budget->autoBudgets()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var AutoBudget $autoBudget */
|
||||
foreach ($set as $autoBudget) {
|
||||
$autoBudget->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d auto budgets for budget #%d.', $set->count(), $budget->id));
|
||||
}
|
||||
|
||||
private function recalculateAvailableBudgets(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
Log::debug('Start with available budgets.');
|
||||
$set = $userGroup->availableBudgets()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var AvailableBudget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$budget->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d available budgets.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateBills(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $userGroup->bills()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($set as $bill) {
|
||||
$bill->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d bills.', $set->count()));
|
||||
}
|
||||
|
||||
private function calculateTransactions(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
// custom query because of the potential size of this update.
|
||||
$set = DB::table('transactions')
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (DatabaseBuilder $q1) use ($currency): void {
|
||||
$q1->where(static function (DatabaseBuilder $q2) use ($currency): void {
|
||||
$q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');
|
||||
})->orWhere(static function (DatabaseBuilder $q3) use ($currency): void {
|
||||
$q3->whereNot('transactions.transaction_currency_id', $currency->id)->whereNot('transactions.foreign_currency_id', $currency->id);
|
||||
});
|
||||
})
|
||||
// ->where(static function (DatabaseBuilder $q) use ($currency): void {
|
||||
// $q->whereNot('transactions.transaction_currency_id', $currency->id)
|
||||
// ->whereNot('transactions.foreign_currency_id', $currency->id)
|
||||
// ;
|
||||
// })
|
||||
->get(['transactions.id'])
|
||||
;
|
||||
TransactionObserver::$recalculate = false;
|
||||
foreach ($set as $item) {
|
||||
// here we are.
|
||||
/** @var null|Transaction $transaction */
|
||||
$transaction = Transaction::find($item->id);
|
||||
$transaction?->touch();
|
||||
}
|
||||
TransactionObserver::$recalculate = true;
|
||||
Log::debug(sprintf('Recalculated %d transactions.', $set->count()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\AccountBalance;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
@@ -47,7 +46,6 @@ class CorrectsTimezoneInformation extends Command
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
public static array $models = [
|
||||
AccountBalance::class => ['date'], // done
|
||||
AvailableBudget::class => ['start_date', 'end_date'], // done
|
||||
Bill::class => ['date', 'end_date', 'extension_date'], // done
|
||||
BudgetLimit::class => ['start_date', 'end_date'], // done
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DestroyedTransactionGroup.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* DestroyedSingleTransactionGroup.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,18 +22,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class DestroyedTransactionGroup.
|
||||
*/
|
||||
class DestroyedTransactionGroup extends Event
|
||||
class DestroyedSingleTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
@@ -40,7 +37,5 @@ class DestroyedTransactionGroup extends Event
|
||||
*/
|
||||
public function __construct(
|
||||
public TransactionGroup $transactionGroup
|
||||
) {
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
}
|
||||
) {}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class TriggeredStoredTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StoredTransactionGroup.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* UpdatedSingleTransactionGroup.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,17 +22,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
namespace FireflyIII\Events\Model\TransactionGroup;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class StoredTransactionGroup.
|
||||
*/
|
||||
class StoredTransactionGroup extends Event
|
||||
class UpdatedSingleTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
@@ -39,7 +37,6 @@ class StoredTransactionGroup extends Event
|
||||
*/
|
||||
public function __construct(
|
||||
public TransactionGroup $transactionGroup,
|
||||
public bool $applyRules,
|
||||
public bool $fireWebhooks
|
||||
public TransactionGroupEventFlags $flags
|
||||
) {}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* UpdatedTransactionGroup.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class UpdatedTransactionGroup.
|
||||
*/
|
||||
class UpdatedTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public TransactionGroup $transactionGroup,
|
||||
public bool $applyRules,
|
||||
public bool $fireWebhooks,
|
||||
public bool $runRecalculations
|
||||
) {}
|
||||
}
|
||||
@@ -109,10 +109,6 @@ class TransactionJournalFactory
|
||||
public function create(array $data): Collection
|
||||
{
|
||||
Log::debug('Now in TransactionJournalFactory::create()');
|
||||
// convert to special object.
|
||||
// $dataObject = new NullArrayObject($data);
|
||||
|
||||
Log::debug('Start of TransactionJournalFactory::create()');
|
||||
$collection = new Collection();
|
||||
$transactions = $data['transactions'] ?? [];
|
||||
if (0 === count($transactions)) {
|
||||
@@ -188,7 +184,6 @@ class TransactionJournalFactory
|
||||
$carbon->setTimezone(config('app.timezone'));
|
||||
|
||||
// 2024-11-19, overrule timezone with UTC and store it as UTC.
|
||||
|
||||
if (true === FireflyConfig::get('utc', false)->data) {
|
||||
$carbon->setTimezone('UTC');
|
||||
}
|
||||
|
||||
46
app/Factory/WebhookMessageFactory.php
Normal file
46
app/Factory/WebhookMessageFactory.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* WebhookMessageFactory.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\Factory;
|
||||
|
||||
use FireflyIII\Models\Webhook;
|
||||
use FireflyIII\Models\WebhookMessage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class WebhookMessageFactory
|
||||
{
|
||||
public function create(Webhook $webhook, array $data): WebhookMessage
|
||||
{
|
||||
$webhookMessage = new WebhookMessage();
|
||||
$webhookMessage->webhook()->associate($webhook);
|
||||
$webhookMessage->sent = false;
|
||||
$webhookMessage->errored = false;
|
||||
$webhookMessage->uuid = $data['uuid'];
|
||||
$webhookMessage->message = $data;
|
||||
$webhookMessage->save();
|
||||
Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id));
|
||||
|
||||
return $webhookMessage;
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,13 @@ namespace FireflyIII\Generator\Webhook;
|
||||
use FireflyIII\Enums\WebhookResponse;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\WebhookMessageFactory;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\Webhook;
|
||||
use FireflyIII\Models\WebhookMessage;
|
||||
use FireflyIII\Models\WebhookResponse as WebhookResponseModel;
|
||||
use FireflyIII\Models\WebhookTrigger as WebhookTriggerModel;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
@@ -254,7 +254,8 @@ class StandardMessageGenerator implements MessageGeneratorInterface
|
||||
$basicMessage['content'][] = $transformer->transform($account);
|
||||
}
|
||||
}
|
||||
$this->storeMessage($webhook, $basicMessage);
|
||||
$factory = new WebhookMessageFactory();
|
||||
$factory->create($webhook, $basicMessage);
|
||||
}
|
||||
|
||||
public function getVersion(): int
|
||||
@@ -277,18 +278,6 @@ class StandardMessageGenerator implements MessageGeneratorInterface
|
||||
return $accounts->unique();
|
||||
}
|
||||
|
||||
private function storeMessage(Webhook $webhook, array $message): void
|
||||
{
|
||||
$webhookMessage = new WebhookMessage();
|
||||
$webhookMessage->webhook()->associate($webhook);
|
||||
$webhookMessage->sent = false;
|
||||
$webhookMessage->errored = false;
|
||||
$webhookMessage->uuid = $message['uuid'];
|
||||
$webhookMessage->message = $message;
|
||||
$webhookMessage->save();
|
||||
Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id));
|
||||
}
|
||||
|
||||
public function setObjects(Collection $objects): void
|
||||
{
|
||||
$this->objects = $objects;
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* APIEventHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Notifications\User\NewAccessToken;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Laravel\Passport\Events\AccessTokenCreated;
|
||||
|
||||
/**
|
||||
* Class APIEventHandler
|
||||
*/
|
||||
class APIEventHandler
|
||||
{
|
||||
/**
|
||||
* Respond to the creation of an access token.
|
||||
*/
|
||||
public function accessTokenCreated(AccessTokenCreated $event): void
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
$user = $repository->find((int) $event->userId);
|
||||
|
||||
if (null !== $user) {
|
||||
try {
|
||||
Notification::send($user, new NewAccessToken());
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StoredGroupEventHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TriggeredStoredTransactionGroup;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class StoredGroupEventHandler
|
||||
*
|
||||
* TODO migrate to observer?
|
||||
*/
|
||||
class StoredGroupEventHandler
|
||||
{
|
||||
public function runAllHandlers(StoredTransactionGroup $event): void
|
||||
{
|
||||
// $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);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method grabs all the users rules and processes them.
|
||||
*/
|
||||
private function processRules(StoredTransactionGroup $storedGroupEvent, ?RuleGroup $ruleGroup): void
|
||||
{
|
||||
if (false === $storedGroupEvent->applyRules) {
|
||||
Log::info(sprintf('Will not run rules on group #%d', $storedGroupEvent->transactionGroup->id));
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug('Now in StoredGroupEventHandler::processRules()');
|
||||
|
||||
$journals = $storedGroupEvent->transactionGroup->transactionJournals;
|
||||
$array = [];
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$array[] = $journal->id;
|
||||
}
|
||||
$journalIds = implode(',', $array);
|
||||
Log::debug(sprintf('Add local operator for journal(s): %s', $journalIds));
|
||||
|
||||
// collect rules:
|
||||
$ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
|
||||
$ruleGroupRepository->setUser($storedGroupEvent->transactionGroup->user);
|
||||
|
||||
// add the groups to the rule engine.
|
||||
// it should run the rules in the group and cancel the group if necessary.
|
||||
if (null === $ruleGroup) {
|
||||
Log::debug('Fire processRules with ALL store-journal rule groups.');
|
||||
$groups = $ruleGroupRepository->getRuleGroupsWithRules('store-journal');
|
||||
}
|
||||
if (null !== $ruleGroup) {
|
||||
Log::debug(sprintf('Fire processRules with rule group #%d.', $ruleGroup->id));
|
||||
$groups = new Collection([$ruleGroup]);
|
||||
}
|
||||
|
||||
// create and fire rule engine.
|
||||
$newRuleEngine = app(RuleEngineInterface::class);
|
||||
$newRuleEngine->setUser($storedGroupEvent->transactionGroup->user);
|
||||
$newRuleEngine->addOperator(['type' => 'journal_id', 'value' => $journalIds]);
|
||||
$newRuleEngine->setRuleGroups($groups);
|
||||
$newRuleEngine->fire();
|
||||
}
|
||||
|
||||
private function recalculateCredit(StoredTransactionGroup $event): void
|
||||
{
|
||||
$group = $event->transactionGroup;
|
||||
|
||||
/** @var CreditRecalculateService $object */
|
||||
$object = app(CreditRecalculateService::class);
|
||||
$object->setGroup($group);
|
||||
$object->recalculate();
|
||||
}
|
||||
|
||||
private function removePeriodStatistics(StoredTransactionGroup $event): void
|
||||
{
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($event->transactionGroup->transactionJournals as $journal) {
|
||||
/** @var null|Transaction $source */
|
||||
$source = $journal->transactions()->where('amount', '<', '0')->first();
|
||||
|
||||
/** @var null|Transaction $dest */
|
||||
$dest = $journal->transactions()->where('amount', '>', '0')->first();
|
||||
|
||||
if (null !== $source) {
|
||||
$repository->deleteStatisticsForModel($source->account, $journal->date);
|
||||
}
|
||||
if (null !== $dest) {
|
||||
$repository->deleteStatisticsForModel($dest->account, $journal->date);
|
||||
}
|
||||
$categories = $journal->categories;
|
||||
$tags = $journal->tags;
|
||||
$budgets = $journal->budgets;
|
||||
foreach ($categories as $category) {
|
||||
$repository->deleteStatisticsForModel($category, $journal->date);
|
||||
}
|
||||
foreach ($tags as $tag) {
|
||||
$repository->deleteStatisticsForModel($tag, $journal->date);
|
||||
}
|
||||
foreach ($budgets as $budget) {
|
||||
$repository->deleteStatisticsForModel($budget, $journal->date);
|
||||
}
|
||||
if (0 === $categories->count()) {
|
||||
$repository->deleteStatisticsForPrefix($journal->userGroup, 'no_category', $journal->date);
|
||||
}
|
||||
if (0 === $budgets->count()) {
|
||||
$repository->deleteStatisticsForPrefix($journal->userGroup, 'no_budget', $journal->date);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method processes all webhooks that respond to the "stored transaction group" trigger (100)
|
||||
*/
|
||||
private function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
$group = $storedGroupEvent->transactionGroup;
|
||||
if (false === $storedGroupEvent->fireWebhooks) {
|
||||
Log::info(sprintf('Will not fire webhooks for transaction group #%d', $group->id));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $group->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(new Collection()->push($group));
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* UpdatedAccountEventHandler.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\UpdatedAccount;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
|
||||
/**
|
||||
* Class UpdatedAccountEventHandler
|
||||
*/
|
||||
class UpdatedAccountEventHandler
|
||||
{
|
||||
public function recalculateCredit(UpdatedAccount $event): void
|
||||
{
|
||||
$account = $event->account;
|
||||
|
||||
/** @var CreditRecalculateService $object */
|
||||
$object = app(CreditRecalculateService::class);
|
||||
$object->setAccount($account);
|
||||
$object->recalculate();
|
||||
}
|
||||
}
|
||||
45
app/Handlers/ExchangeRate/ConversionParameters.php
Normal file
45
app/Handlers/ExchangeRate/ConversionParameters.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ConversionParameters.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\Handlers\ExchangeRate;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ConversionParameters
|
||||
{
|
||||
public User $user;
|
||||
public Model $model;
|
||||
public ?TransactionCurrency $originalCurrency = null;
|
||||
public string $amountField;
|
||||
public string $primaryAmountField;
|
||||
public Carbon $date;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date = now();
|
||||
}
|
||||
}
|
||||
104
app/Handlers/ExchangeRate/ConvertsAmountToPrimaryAmount.php
Normal file
104
app/Handlers/ExchangeRate/ConvertsAmountToPrimaryAmount.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ConvertsAmountToPrimaryAmount.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\Handlers\ExchangeRate;
|
||||
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ConvertsAmountToPrimaryAmount
|
||||
{
|
||||
public static function convert(ConversionParameters $params): void
|
||||
{
|
||||
$amountField = $params->amountField;
|
||||
$primaryAmountField = $params->primaryAmountField;
|
||||
|
||||
if (!Amount::convertToPrimary($params->user)) {
|
||||
Log::debug(sprintf(
|
||||
'User does not want to do conversion, no need to convert %s and store it in field %s for %s #%d.',
|
||||
$params->amountField,
|
||||
$params->primaryAmountField,
|
||||
get_class($params->model),
|
||||
$params->model->id
|
||||
));
|
||||
$params->model->{$primaryAmountField} = null;
|
||||
$params->model->saveQuietly();
|
||||
|
||||
return;
|
||||
}
|
||||
if (null === $params->originalCurrency) {
|
||||
Log::debug(sprintf(
|
||||
'Original currency field is empty, no need to convert %s and store it in field %s for %s #%d.',
|
||||
$params->amountField,
|
||||
$params->primaryAmountField,
|
||||
get_class($params->model),
|
||||
$params->model->id
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
$primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($params->user->userGroup);
|
||||
Log::debug(sprintf(
|
||||
'Will convert amount in field %s from %s to %s and store it in %s',
|
||||
$params->originalCurrency->code,
|
||||
$primaryCurrency->code,
|
||||
$params->amountField,
|
||||
$params->primaryAmountField
|
||||
));
|
||||
if ($params->originalCurrency->id === $primaryCurrency->id) {
|
||||
Log::debug('Both currencies are the same, do nothing.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// field is empty or zero, do nothing.
|
||||
$amount = (string) $params->model->{$amountField};
|
||||
if ('' === $amount || 0 === bccomp($amount, '0')) {
|
||||
Log::debug(sprintf('Amount "%s" in field "%s" cannot be used, do nothing.', $amount, $amountField));
|
||||
$params->model->{$amountField} = null;
|
||||
$params->model->{$primaryAmountField} = null;
|
||||
$params->model->saveQuietly();
|
||||
|
||||
return;
|
||||
}
|
||||
$converter = new ExchangeRateConverter();
|
||||
$newAmount = $converter->convert($params->originalCurrency, $primaryCurrency, now(), $amount);
|
||||
$converter->setUserGroup($params->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$params->model->{$primaryAmountField} = $newAmount;
|
||||
$params->model->saveQuietly();
|
||||
Log::debug(sprintf(
|
||||
'Converted field "%s" of %s #%d from %s %s to %s %s (in field "%s")',
|
||||
$amountField,
|
||||
get_class($params->model),
|
||||
$params->model->id,
|
||||
$params->originalCurrency->code,
|
||||
$amount,
|
||||
$primaryCurrency->code,
|
||||
$newAmount,
|
||||
$primaryAmountField
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class AutoBudgetObserver
|
||||
@@ -37,26 +37,20 @@ class AutoBudgetObserver
|
||||
$this->updatePrimaryCurrencyAmount($autoBudget);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(AutoBudget $autoBudget): void
|
||||
{
|
||||
if (!Amount::convertToPrimary($autoBudget->budget->user)) {
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($autoBudget->budget->user->userGroup);
|
||||
$autoBudget->native_amount = null;
|
||||
if ($autoBudget->transactionCurrency->id !== $userCurrency->id) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($autoBudget->budget->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$autoBudget->native_amount = $converter->convert($autoBudget->transactionCurrency, $userCurrency, today(), $autoBudget->amount);
|
||||
}
|
||||
$autoBudget->saveQuietly();
|
||||
Log::debug('Auto budget primary currency amount is updated.');
|
||||
}
|
||||
|
||||
public function updated(AutoBudget $autoBudget): void
|
||||
{
|
||||
Log::debug('Observe "updated" of an auto budget.');
|
||||
$this->updatePrimaryCurrencyAmount($autoBudget);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(AutoBudget $autoBudget): void
|
||||
{
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $autoBudget->budget->user;
|
||||
$params->model = $autoBudget;
|
||||
$params->originalCurrency = $autoBudget->transactionCurrency;
|
||||
$params->amountField = 'amount';
|
||||
$params->primaryAmountField = 'native_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,41 +24,30 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class AvailableBudgetObserver
|
||||
{
|
||||
public function created(AvailableBudget $availableBudget): void
|
||||
{
|
||||
// Log::debug('Observe "created" of an available budget.');
|
||||
$this->updatePrimaryCurrencyAmount($availableBudget);
|
||||
}
|
||||
|
||||
public function updated(AvailableBudget $availableBudget): void
|
||||
{
|
||||
$this->updatePrimaryCurrencyAmount($availableBudget);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(AvailableBudget $availableBudget): void
|
||||
{
|
||||
if (!Amount::convertToPrimary($availableBudget->user)) {
|
||||
// Log::debug('Do not update primary currency available amount of the available budget.');
|
||||
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($availableBudget->user->userGroup);
|
||||
$availableBudget->native_amount = null;
|
||||
if ($availableBudget->transactionCurrency->id !== $userCurrency->id) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($availableBudget->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$availableBudget->native_amount = $converter->convert($availableBudget->transactionCurrency, $userCurrency, today(), $availableBudget->amount);
|
||||
}
|
||||
$availableBudget->saveQuietly();
|
||||
Log::debug('Available budget primary currency amount is updated.');
|
||||
}
|
||||
|
||||
public function updated(AvailableBudget $availableBudget): void
|
||||
{
|
||||
// Log::debug('Observe "updated" of an available budget.');
|
||||
$this->updatePrimaryCurrencyAmount($availableBudget);
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $availableBudget->user;
|
||||
$params->model = $availableBudget;
|
||||
$params->originalCurrency = $availableBudget->transactionCurrency;
|
||||
$params->amountField = 'amount';
|
||||
$params->primaryAmountField = 'native_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class BillObserver
|
||||
@@ -37,35 +36,14 @@ class BillObserver
|
||||
{
|
||||
public function created(Bill $bill): void
|
||||
{
|
||||
// Log::debug('Observe "created" of a bill.');
|
||||
$this->updatePrimaryCurrencyAmount($bill);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(Bill $bill): void
|
||||
{
|
||||
if (!Amount::convertToPrimary($bill->user)) {
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($bill->user->userGroup);
|
||||
$bill->native_amount_min = null;
|
||||
$bill->native_amount_max = null;
|
||||
if ($bill->transactionCurrency->id !== $userCurrency->id) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($bill->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$bill->native_amount_min = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_min);
|
||||
$bill->native_amount_max = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_max);
|
||||
}
|
||||
$bill->saveQuietly();
|
||||
Log::debug('Bill primary currency amounts are updated.');
|
||||
}
|
||||
|
||||
public function deleting(Bill $bill): void
|
||||
{
|
||||
$repository = app(AttachmentRepositoryInterface::class);
|
||||
$repository->setUser($bill->user);
|
||||
|
||||
// Log::debug('Observe "deleting" of a bill.');
|
||||
/** @var Attachment $attachment */
|
||||
foreach ($bill->attachments()->get() as $attachment) {
|
||||
$repository->destroy($attachment);
|
||||
@@ -78,4 +56,20 @@ class BillObserver
|
||||
// Log::debug('Observe "updated" of a bill.');
|
||||
$this->updatePrimaryCurrencyAmount($bill);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(Bill $bill): void
|
||||
{
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $bill->user;
|
||||
$params->model = $bill;
|
||||
$params->originalCurrency = $bill->transactionCurrency;
|
||||
$params->amountField = 'amount_min';
|
||||
$params->primaryAmountField = 'native_amount_min';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
|
||||
// and again!
|
||||
$params->amountField = 'amount_max';
|
||||
$params->primaryAmountField = 'native_amount_max';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace FireflyIII\Handlers\Observer;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
|
||||
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -44,18 +44,30 @@ class BudgetLimitObserver
|
||||
Log::debug('Observe "created" of a budget limit.');
|
||||
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
||||
$this->updateAvailableBudget($budgetLimit);
|
||||
$this->sendWebhookMessages('fire_webhooks_bl_store', WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT, $budgetLimit);
|
||||
}
|
||||
|
||||
public function updated(BudgetLimit $budgetLimit): void
|
||||
{
|
||||
Log::debug('Observe "updated" of a budget limit.');
|
||||
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
||||
$this->updateAvailableBudget($budgetLimit);
|
||||
$this->sendWebhookMessages('fire_webhooks_bl_update', WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT, $budgetLimit);
|
||||
}
|
||||
|
||||
private function sendWebhookMessages(string $key, WebhookTrigger $trigger, BudgetLimit $budgetLimit): void
|
||||
{
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
if (true === $singleton->getPreference('fire_webhooks_bl_store')) {
|
||||
if (true === $singleton->getPreference($key)) {
|
||||
$user = $budgetLimit->budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->setTrigger($trigger);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
@@ -65,44 +77,12 @@ class BudgetLimitObserver
|
||||
|
||||
private function updatePrimaryCurrencyAmount(BudgetLimit $budgetLimit): void
|
||||
{
|
||||
if (!Amount::convertToPrimary($budgetLimit->budget->user)) {
|
||||
// Log::debug('Do not update primary currency amount of the budget limit.');
|
||||
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($budgetLimit->budget->user->userGroup);
|
||||
$budgetLimit->native_amount = null;
|
||||
if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($budgetLimit->budget->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$budgetLimit->native_amount = $converter->convert($budgetLimit->transactionCurrency, $userCurrency, today(), $budgetLimit->amount);
|
||||
}
|
||||
$budgetLimit->saveQuietly();
|
||||
Log::debug('Budget limit primary currency amounts are updated.');
|
||||
}
|
||||
|
||||
public function updated(BudgetLimit $budgetLimit): void
|
||||
{
|
||||
Log::debug('Observe "updated" of a budget limit.');
|
||||
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
||||
$this->updateAvailableBudget($budgetLimit);
|
||||
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
if (true === $singleton->getPreference('fire_webhooks_bl_update')) {
|
||||
$user = $budgetLimit->budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $budgetLimit->budget->user;
|
||||
$params->model = $budgetLimit;
|
||||
$params->originalCurrency = $budgetLimit->transactionCurrency;
|
||||
$params->amountField = 'amount';
|
||||
$params->primaryAmountField = 'native_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,27 +64,6 @@ class BudgetObserver
|
||||
}
|
||||
}
|
||||
|
||||
public function updated(Budget $budget): void
|
||||
{
|
||||
Log::debug(sprintf('Observe "updated" of budget #%d ("%s").', $budget->id, $budget->name));
|
||||
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
if (true === $singleton->getPreference('fire_webhooks_budget_update')) {
|
||||
$user = $budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
|
||||
public function deleting(Budget $budget): void
|
||||
{
|
||||
Log::debug('Observe "deleting" of a budget.');
|
||||
@@ -123,4 +102,25 @@ class BudgetObserver
|
||||
|
||||
// recalculate available budgets.
|
||||
}
|
||||
|
||||
public function updated(Budget $budget): void
|
||||
{
|
||||
Log::debug(sprintf('Observe "updated" of budget #%d ("%s").', $budget->id, $budget->name));
|
||||
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
if (true === $singleton->getPreference('fire_webhooks_budget_update')) {
|
||||
$user = $budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,8 @@ use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AccountObserver
|
||||
*/
|
||||
class AccountObserver
|
||||
class DeletedAccountObserver
|
||||
{
|
||||
/**
|
||||
* Also delete related objects.
|
||||
*/
|
||||
public function deleting(Account $account): void
|
||||
{
|
||||
Log::debug('Observe "deleting" of an account.');
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class AttachmentObserver
|
||||
*/
|
||||
class AttachmentObserver
|
||||
class DeletedAttachmentObserver
|
||||
{
|
||||
public function deleting(Attachment $attachment): void
|
||||
{
|
||||
@@ -31,7 +31,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class CategoryObserver
|
||||
*/
|
||||
class CategoryObserver
|
||||
class DeletedCategoryObserver
|
||||
{
|
||||
public function deleting(Category $category): void
|
||||
{
|
||||
@@ -31,7 +31,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class RecurrenceObserver
|
||||
*/
|
||||
class RecurrenceObserver
|
||||
class DeletedRecurrenceObserver
|
||||
{
|
||||
public function deleting(Recurrence $recurrence): void
|
||||
{
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class RecurrenceTransactionObserver
|
||||
*/
|
||||
class RecurrenceTransactionObserver
|
||||
class DeletedRecurrenceTransactionObserver
|
||||
{
|
||||
public function deleting(RecurrenceTransaction $transaction): void
|
||||
{
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class RuleGroupObserver
|
||||
*/
|
||||
class RuleGroupObserver
|
||||
class DeletedRuleGroupObserver
|
||||
{
|
||||
public function deleting(RuleGroup $ruleGroup): void
|
||||
{
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class RuleObserver
|
||||
*/
|
||||
class RuleObserver
|
||||
class DeletedRuleObserver
|
||||
{
|
||||
public function deleting(Rule $rule): void
|
||||
{
|
||||
@@ -31,7 +31,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class TagObserver
|
||||
*/
|
||||
class TagObserver
|
||||
class DeletedTagObserver
|
||||
{
|
||||
public function deleting(Tag $tag): void
|
||||
{
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class TransactionGroup
|
||||
*/
|
||||
class TransactionGroupObserver
|
||||
class DeletedTransactionGroupObserver
|
||||
{
|
||||
public function deleting(TransactionGroup $transactionGroup): void
|
||||
{
|
||||
@@ -33,7 +33,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class TransactionJournalObserver
|
||||
*/
|
||||
class TransactionJournalObserver
|
||||
class DeletedTransactionJournalObserver
|
||||
{
|
||||
public function deleting(TransactionJournal $transactionJournal): void
|
||||
{
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class WebhookMessageObserver
|
||||
*/
|
||||
class WebhookMessageObserver
|
||||
class DeletedWebhookMessageObserver
|
||||
{
|
||||
public function deleting(WebhookMessage $webhookMessage): void
|
||||
{
|
||||
@@ -29,7 +29,7 @@ use Illuminate\Support\Facades\Log;
|
||||
/**
|
||||
* Class WebhookObserver
|
||||
*/
|
||||
class WebhookObserver
|
||||
class DeletedWebhookObserver
|
||||
{
|
||||
public function deleting(Webhook $webhook): void
|
||||
{
|
||||
@@ -24,9 +24,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PiggyBankEventObserver
|
||||
@@ -37,32 +37,27 @@ class PiggyBankEventObserver
|
||||
$this->updatePrimaryCurrencyAmount($event);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(PiggyBankEvent $event): void
|
||||
{
|
||||
$user = $event->piggyBank->accounts()->first()?->user;
|
||||
if (null === $user) {
|
||||
Log::warning('Piggy bank seems to have no accounts. Break.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (!Amount::convertToPrimary($user)) {
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
|
||||
$event->native_amount = null;
|
||||
if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$event->native_amount = $converter->convert($event->piggyBank->transactionCurrency, $userCurrency, today(), $event->amount);
|
||||
}
|
||||
$event->saveQuietly();
|
||||
Log::debug('Piggy bank event primary currency amount is updated.');
|
||||
}
|
||||
|
||||
public function updated(PiggyBankEvent $event): void
|
||||
{
|
||||
Log::debug('Observe "updated" of a piggy bank event.');
|
||||
$this->updatePrimaryCurrencyAmount($event);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(PiggyBankEvent $event): void
|
||||
{
|
||||
$user = $event->piggyBank->accounts()->first()?->user;
|
||||
if (null === $user) {
|
||||
Log::warning('Piggy bank seems to have no accounts. Break.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $user;
|
||||
$params->model = $event;
|
||||
$params->originalCurrency = $event->piggyBank->transactionCurrency;
|
||||
$params->amountField = 'amount';
|
||||
$params->primaryAmountField = 'native_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -42,26 +42,6 @@ class PiggyBankObserver
|
||||
$this->updatePrimaryCurrencyAmount($piggyBank);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(PiggyBank $piggyBank): void
|
||||
{
|
||||
$group = $piggyBank->accounts()->first()?->user->userGroup;
|
||||
if (null === $group) {
|
||||
Log::debug(sprintf('No account(s) yet for piggy bank #%d.', $piggyBank->id));
|
||||
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($group);
|
||||
$piggyBank->native_target_amount = null;
|
||||
if ($piggyBank->transactionCurrency->id !== $userCurrency->id) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setIgnoreSettings(true);
|
||||
$converter->setUserGroup($group);
|
||||
$piggyBank->native_target_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $piggyBank->target_amount);
|
||||
}
|
||||
$piggyBank->saveQuietly();
|
||||
Log::debug('Piggy bank primary currency target amount is updated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Also delete related objects.
|
||||
*/
|
||||
@@ -88,4 +68,22 @@ class PiggyBankObserver
|
||||
Log::debug('Observe "updated" of a piggy bank.');
|
||||
$this->updatePrimaryCurrencyAmount($piggyBank);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(PiggyBank $piggyBank): void
|
||||
{
|
||||
$group = $piggyBank->accounts()->first()?->user->userGroup;
|
||||
if (null === $group) {
|
||||
Log::debug(sprintf('No account(s) yet for piggy bank #%d.', $piggyBank->id));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $piggyBank->accounts()->first()?->user;
|
||||
$params->model = $piggyBank;
|
||||
$params->originalCurrency = $piggyBank->transactionCurrency;
|
||||
$params->amountField = 'target_amount';
|
||||
$params->primaryAmountField = 'native_target_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Observer;
|
||||
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -39,55 +37,10 @@ class TransactionObserver
|
||||
|
||||
public function created(Transaction $transaction): void
|
||||
{
|
||||
return;
|
||||
|
||||
Log::debug(sprintf('Observed creation of Transaction #%d.', $transaction->id));
|
||||
$this->updatePrimaryCurrencyAmount($transaction);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(Transaction $transaction): void
|
||||
{
|
||||
if (!Amount::convertToPrimary($transaction->transactionJournal->user)) {
|
||||
return;
|
||||
}
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($transaction->transactionJournal->user->userGroup);
|
||||
$transaction->native_amount = null;
|
||||
$transaction->native_foreign_amount = null;
|
||||
// first normal amount
|
||||
if (
|
||||
$transaction->transactionCurrency->id !== $userCurrency->id
|
||||
&& (
|
||||
null === $transaction->foreign_currency_id
|
||||
|| null !== $transaction->foreign_currency_id
|
||||
&& $transaction->foreign_currency_id !== $userCurrency->id
|
||||
)
|
||||
) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($transaction->transactionJournal->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$transaction->native_amount = $converter->convert(
|
||||
$transaction->transactionCurrency,
|
||||
$userCurrency,
|
||||
$transaction->transactionJournal->date,
|
||||
$transaction->amount
|
||||
);
|
||||
}
|
||||
// then foreign amount
|
||||
if ($transaction->foreignCurrency?->id !== $userCurrency->id && null !== $transaction->foreign_amount && null !== $transaction->foreignCurrency) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($transaction->transactionJournal->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$transaction->native_foreign_amount = $converter->convert(
|
||||
$transaction->foreignCurrency,
|
||||
$userCurrency,
|
||||
$transaction->transactionJournal->date,
|
||||
$transaction->foreign_amount
|
||||
);
|
||||
}
|
||||
|
||||
$transaction->saveQuietly();
|
||||
Log::debug(sprintf('Transaction #%d primary currency amounts are updated.', $transaction->id));
|
||||
}
|
||||
|
||||
public function deleting(?Transaction $transaction): void
|
||||
{
|
||||
Log::debug('Observe "deleting" of a transaction.');
|
||||
@@ -96,15 +49,29 @@ class TransactionObserver
|
||||
|
||||
public function updated(Transaction $transaction): void
|
||||
{
|
||||
// Log::debug('Observe "updated" of a transaction.');
|
||||
if (
|
||||
true === FireflyConfig::get('use_running_balance', config('firefly.feature_flags.running_balance_column'))->data
|
||||
&& self::$recalculate
|
||||
&& 1 === bccomp($transaction->amount, '0')
|
||||
) {
|
||||
Log::debug('Trigger recalculateForJournal');
|
||||
AccountBalanceCalculator::recalculateForJournal($transaction->transactionJournal);
|
||||
}
|
||||
$this->updatePrimaryCurrencyAmount($transaction);
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(Transaction $transaction): void
|
||||
{
|
||||
// convert "amount" to "native_amount"
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $transaction->transactionJournal->user;
|
||||
$params->model = $transaction;
|
||||
$params->originalCurrency = $transaction->transactionCurrency;
|
||||
$params->amountField = 'amount';
|
||||
$params->date = $transaction->transactionJournal->date;
|
||||
$params->primaryAmountField = 'native_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
|
||||
// convert "foreign_amount" to "native_foreign_amount"
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $transaction->transactionJournal->user;
|
||||
$params->model = $transaction;
|
||||
$params->originalCurrency = $transaction->foreignCurrency;
|
||||
$params->date = $transaction->transactionJournal->date;
|
||||
$params->amountField = 'foreign_amount';
|
||||
$params->primaryAmountField = 'native_foreign_amount';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\BulkEditJournalRequest;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -115,10 +116,12 @@ class BulkController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
|
||||
// run rules on changed journals:
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($collection as $journal) { // @phpstan-ignore-line
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, false));
|
||||
foreach ($collection as $journal) {
|
||||
event(new UpdatedSingleTransactionGroup($journal->transactionGroup, $flags));
|
||||
}
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
||||
use Exception;
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -305,7 +306,8 @@ class ConvertController extends Controller
|
||||
$group->refresh();
|
||||
|
||||
session()->flash('success', (string) trans('firefly.converted_to_'.$destinationType->type));
|
||||
event(new UpdatedTransactionGroup($group, true, true, true));
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
event(new UpdatedSingleTransactionGroup($group, $flags));
|
||||
|
||||
return redirect(route('transactions.show', [$group->id]));
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ class CreateController extends Controller
|
||||
// event!
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
event(new CreatedSingleTransactionGroup($group, $flags));
|
||||
// event(new StoredTransactionGroup($newGroup, true, true));
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\MassDeleteJournalRequest;
|
||||
@@ -194,15 +195,15 @@ class MassController extends Controller
|
||||
*/
|
||||
private function updateJournal(int $journalId, MassEditJournalRequest $request): void
|
||||
{
|
||||
$journal = $this->repository->find($journalId);
|
||||
$journal = $this->repository->find($journalId);
|
||||
if (!$journal instanceof TransactionJournal) {
|
||||
throw new FireflyException(sprintf('Trying to edit non-existent or deleted journal #%d', $journalId));
|
||||
}
|
||||
$service = app(JournalUpdateService::class);
|
||||
$service = app(JournalUpdateService::class);
|
||||
// for each field, call the update service.
|
||||
$service->setTransactionJournal($journal);
|
||||
|
||||
$data = [
|
||||
$data = [
|
||||
'date' => $this->getDateFromRequest($request, $journal->id, 'date'),
|
||||
'description' => $this->getStringFromRequest($request, $journal->id, 'description'),
|
||||
'source_id' => $this->getIntFromRequest($request, $journal->id, 'source_id'),
|
||||
@@ -220,8 +221,10 @@ class MassController extends Controller
|
||||
$service->setData($data);
|
||||
$service->update();
|
||||
// trigger rules
|
||||
$runRecalculations = $service->isCompareHashChanged();
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, $runRecalculations));
|
||||
$runRecalculations = $service->isCompareHashChanged();
|
||||
$flags = new TransactionGroupEventFlags();
|
||||
$flags->recalculateCredit = $runRecalculations;
|
||||
event(new UpdatedSingleTransactionGroup($journal->transactionGroup, $flags));
|
||||
}
|
||||
|
||||
private function getDateFromRequest(MassEditJournalRequest $request, int $journalId, string $key): ?Carbon
|
||||
|
||||
@@ -26,14 +26,15 @@ namespace FireflyIII\Listeners\Model\Account;
|
||||
|
||||
use FireflyIII\Events\Model\Account\CreatedNewAccount;
|
||||
use FireflyIII\Events\Model\Account\UpdatedExistingAccount;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
|
||||
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UpdatesAccountInformation
|
||||
class UpdatesAccountInformation implements ShouldQueue
|
||||
{
|
||||
public function handle(CreatedNewAccount|UpdatedExistingAccount $event): void
|
||||
{
|
||||
@@ -43,7 +44,7 @@ class UpdatesAccountInformation
|
||||
|
||||
private function recalculateCredit(Account $account): void
|
||||
{
|
||||
Log::debug('Will call CreditRecalculateService because a new account was created.');
|
||||
Log::debug('Will call CreditRecalculateService because a new account was created or updated.');
|
||||
|
||||
/** @var CreditRecalculateService $object */
|
||||
$object = app(CreditRecalculateService::class);
|
||||
@@ -53,32 +54,21 @@ class UpdatesAccountInformation
|
||||
|
||||
private function updateVirtualBalance(Account $account): void
|
||||
{
|
||||
if (!Amount::convertToPrimary($account->user)) {
|
||||
Log::debug('After account creation, no need to convert virtual balance.');
|
||||
Log::debug('Will updateVirtualBalance');
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$currency = $repository->getAccountCurrency($account);
|
||||
|
||||
return;
|
||||
if (null !== $currency) {
|
||||
// only when the account has a currency, because that is the only way for the
|
||||
// account to have a virtual balance.
|
||||
$params = new ConversionParameters();
|
||||
$params->user = $account->user;
|
||||
$params->model = $account;
|
||||
$params->originalCurrency = $currency;
|
||||
$params->amountField = 'virtual_balance';
|
||||
$params->primaryAmountField = 'native_virtual_balance';
|
||||
ConvertsAmountToPrimaryAmount::convert($params);
|
||||
Log::debug('Account primary currency virtual balance is updated.');
|
||||
}
|
||||
Log::debug('After account creation, convert virtual balance.');
|
||||
$userCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup);
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$currency = $repository->getAccountCurrency($account);
|
||||
if (
|
||||
null !== $currency
|
||||
&& $currency->id !== $userCurrency->id
|
||||
&& '' !== (string) $account->virtual_balance
|
||||
&& 0 !== bccomp($account->virtual_balance, '0')
|
||||
) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($account->user->userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$account->native_virtual_balance = $converter->convert($currency, $userCurrency, today(), $account->virtual_balance);
|
||||
}
|
||||
if ('' === (string) $account->virtual_balance || 0 === bccomp($account->virtual_balance, '0')) {
|
||||
$account->virtual_balance = null;
|
||||
$account->native_virtual_balance = null;
|
||||
}
|
||||
$account->saveQuietly();
|
||||
|
||||
// Log::debug('Account primary currency virtual balance is updated.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,11 @@ namespace FireflyIII\Listeners\Model\Rule;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\User\RuleActionFailed;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutFailedRuleAction implements ShouldQueue
|
||||
{
|
||||
@@ -58,11 +57,6 @@ class NotifiesUserAboutFailedRuleAction implements ShouldQueue
|
||||
$ruleTitle = $rule->title;
|
||||
$ruleLink = route('rules.edit', [$rule->id]);
|
||||
$params = [$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink];
|
||||
|
||||
try {
|
||||
Notification::send($user, new RuleActionFailed($params));
|
||||
} catch (ClientException $e) {
|
||||
Log::error(sprintf('[a] Error sending notification that the rule action failed: %s', $e->getMessage()));
|
||||
}
|
||||
NotificationSender::send($user, new RuleActionFailed($params));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Model\Subscription;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Model\Subscription\SubscriptionNeedsExtensionOrRenewal;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\User\BillReminder;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesAboutExtensionOrRenewal implements ShouldQueue
|
||||
{
|
||||
@@ -44,24 +43,7 @@ class NotifiesAboutExtensionOrRenewal implements ShouldQueue
|
||||
|
||||
if (true === $preference) {
|
||||
Log::debug('Subscription reminder is true!');
|
||||
|
||||
try {
|
||||
Notification::send($subscription->user, new BillReminder($subscription, $event->field, $event->diff));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($subscription->user, new BillReminder($subscription, $event->field, $event->diff));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Model\Subscription;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Model\Subscription\SubscriptionsAreOverdueForPayment;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\User\SubscriptionsOverdueReminder;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesAboutOverdueSubscriptions implements ShouldQueue
|
||||
{
|
||||
@@ -78,23 +77,6 @@ class NotifiesAboutOverdueSubscriptions implements ShouldQueue
|
||||
Preferences::setForUser($bill->user, $key, true);
|
||||
}
|
||||
Log::warning('should hit this ONCE');
|
||||
|
||||
try {
|
||||
Notification::send($user, new SubscriptionsOverdueReminder($toBeWarned));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new SubscriptionsOverdueReminder($toBeWarned));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,16 +24,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Model\TransactionGroup;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Model\TransactionGroup\TransactionGroupsRequestedReporting;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
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 MailsNewTransactionsReport implements ShouldQueue
|
||||
{
|
||||
@@ -71,23 +70,7 @@ class MailsNewTransactionsReport implements ShouldQueue
|
||||
$groups[] = $transformer->transformObject($group);
|
||||
}
|
||||
|
||||
try {
|
||||
Notification::send($user, new TransactionCreation($groups));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new TransactionCreation($groups));
|
||||
Log::debug('If there is no error above this line, message was sent.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* DestroyedGroupEventHandler.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
* ProcessesDestroyedTransactionGroup.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,31 +22,27 @@
|
||||
* 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 FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\DestroyedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\DestroyedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class DestroyedGroupEventHandler
|
||||
*/
|
||||
class DestroyedGroupEventHandler
|
||||
class ProcessesDestroyedTransactionGroup implements ShouldQueue
|
||||
{
|
||||
public function runAllHandlers(DestroyedTransactionGroup $event): void
|
||||
public function handle(DestroyedSingleTransactionGroup $event): void
|
||||
{
|
||||
$this->triggerWebhooks($event);
|
||||
$this->updateRunningBalance($event);
|
||||
}
|
||||
|
||||
private function triggerWebhooks(DestroyedTransactionGroup $destroyedGroupEvent): void
|
||||
private function triggerWebhooks(DestroyedSingleTransactionGroup $destroyedGroupEvent): void
|
||||
{
|
||||
Log::debug('DestroyedTransactionGroup:triggerWebhooks');
|
||||
$group = $destroyedGroupEvent->transactionGroup;
|
||||
@@ -60,7 +58,7 @@ class DestroyedGroupEventHandler
|
||||
event(new WebhookMessagesRequestSending());
|
||||
}
|
||||
|
||||
private function updateRunningBalance(DestroyedTransactionGroup $event): void
|
||||
private function updateRunningBalance(DestroyedSingleTransactionGroup $event): void
|
||||
{
|
||||
if (false === FireflyConfig::get('use_running_balance', config('firefly.feature_flags.running_balance_column'))->data) {
|
||||
return;
|
||||
@@ -68,7 +68,7 @@ class ProcessesNewTransactionGroup implements ShouldQueue
|
||||
}
|
||||
Log::debug(sprintf('Will (joined with group #%d) collect all open transaction groups and process them.', $groupId));
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$set = $collection->merge($repository->getUncompletedJournals());
|
||||
$set = $collection->merge($repository->getAllUncompletedJournals());
|
||||
if (0 === $set->count()) {
|
||||
Log::debug('Set is empty, never mind.');
|
||||
|
||||
@@ -94,7 +94,7 @@ class ProcessesNewTransactionGroup implements ShouldQueue
|
||||
$this->fireWebhooks($set);
|
||||
}
|
||||
// always remove old relevant statistics.
|
||||
$this->removePeriodStatistics($set);
|
||||
self::removePeriodStatistics($set);
|
||||
|
||||
// recalculate running balance if necessary.
|
||||
if (true === FireflyConfig::get('use_running_balance', config('firefly.feature_flags.running_balance_column'))->data) {
|
||||
@@ -104,30 +104,34 @@ class ProcessesNewTransactionGroup implements ShouldQueue
|
||||
$repository->markAsCompleted($set);
|
||||
}
|
||||
|
||||
private function recalculateRunningBalance(Collection $set): void
|
||||
private function getFromInternalDate(array $ids): Carbon
|
||||
{
|
||||
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();
|
||||
$entries = TransactionJournalMeta::whereIn('transaction_journal_id', $ids)->where('name', '_internal_previous_date')->get(['journal_meta.*']);
|
||||
$array = $entries->toArray();
|
||||
$return = today()->subDay();
|
||||
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']);
|
||||
|
||||
/** @var Carbon $earliest */
|
||||
$earliest = $date->lt($earliest) ? $date : $earliest;
|
||||
$date = Carbon::parse($array[0]['data']);
|
||||
$return = $date->lt($return) ? $date : $return;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
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();
|
||||
$fromInternalDate = $this->getFromInternalDate($set->pluck('id')->toArray());
|
||||
$earliest = $fromInternalDate->lt($earliest) ? $fromInternalDate : $earliest;
|
||||
Log::debug(sprintf('Found earliest date: %s', $earliest->toW3cString()));
|
||||
|
||||
// get accounts
|
||||
$accounts = Account::leftJoin('transactions', 'transactions.account_id', 'accounts.id')
|
||||
$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())
|
||||
@@ -139,13 +143,15 @@ class ProcessesNewTransactionGroup implements ShouldQueue
|
||||
AccountBalanceCalculator::optimizedCalculation($accounts, $earliest);
|
||||
}
|
||||
|
||||
private function removePeriodStatistics(Collection $set): void
|
||||
public static function removePeriodStatistics(Collection $set): void
|
||||
{
|
||||
Log::debug('Always remove period statistics');
|
||||
if (auth()->check()) {
|
||||
Log::debug('Always remove period statistics');
|
||||
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
$repository->deleteStatisticsForCollection($set);
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
$repository->deleteStatisticsForCollection($set);
|
||||
}
|
||||
}
|
||||
|
||||
private function fireWebhooks(Collection $set): void
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* UpdatedGroupEventHandler.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ProcessesUpdatedTransactionGroup.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -19,19 +21,17 @@
|
||||
* 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\Model\TransactionGroup;
|
||||
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Enums\WebhookTrigger;
|
||||
use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup;
|
||||
use FireflyIII\Events\Model\Webhook\WebhookMessagesRequestSending;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
@@ -40,71 +40,31 @@ use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class UpdatedGroupEventHandler
|
||||
*/
|
||||
class UpdatedGroupEventHandler
|
||||
class ProcessesUpdatedTransactionGroup
|
||||
{
|
||||
public function runAllHandlers(UpdatedTransactionGroup $event): void
|
||||
public function handle(UpdatedSingleTransactionGroup $event): void
|
||||
{
|
||||
Log::debug('Now in handle() for UpdatedSingleTransactionGroup');
|
||||
$this->unifyAccounts($event);
|
||||
$this->processRules($event);
|
||||
$this->recalculateCredit($event);
|
||||
$this->triggerWebhooks($event);
|
||||
$this->removePeriodStatistics($event);
|
||||
if ($event->runRecalculations) {
|
||||
$this->updateRunningBalance($event);
|
||||
}
|
||||
}
|
||||
ProcessesNewTransactionGroup::removePeriodStatistics($event->transactionGroup->transactionJournals);
|
||||
$this->updateRunningBalance($event);
|
||||
|
||||
/**
|
||||
* TODO duplicate
|
||||
*/
|
||||
private function removePeriodStatistics(UpdatedTransactionGroup $event): void
|
||||
{
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($event->transactionGroup->transactionJournals as $journal) {
|
||||
$source = $journal->transactions()->where('amount', '<', '0')->first();
|
||||
$dest = $journal->transactions()->where('amount', '>', '0')->first();
|
||||
if (null !== $source) {
|
||||
$repository->deleteStatisticsForModel($source->account, $journal->date);
|
||||
}
|
||||
if (null !== $dest) {
|
||||
$repository->deleteStatisticsForModel($dest->account, $journal->date);
|
||||
}
|
||||
|
||||
$categories = $journal->categories;
|
||||
$tags = $journal->tags;
|
||||
$budgets = $journal->budgets;
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$repository->deleteStatisticsForModel($category, $journal->date);
|
||||
}
|
||||
foreach ($tags as $tag) {
|
||||
$repository->deleteStatisticsForModel($tag, $journal->date);
|
||||
}
|
||||
foreach ($budgets as $budget) {
|
||||
$repository->deleteStatisticsForModel($budget, $journal->date);
|
||||
}
|
||||
if (0 === $categories->count()) {
|
||||
$repository->deleteStatisticsForPrefix($journal->userGroup, 'no_category', $journal->date);
|
||||
}
|
||||
if (0 === $budgets->count()) {
|
||||
$repository->deleteStatisticsForPrefix($journal->userGroup, 'no_budget', $journal->date);
|
||||
}
|
||||
}
|
||||
Log::debug('Done with handle() for UpdatedSingleTransactionGroup');
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will make sure all source / destination accounts are the same.
|
||||
*/
|
||||
public function unifyAccounts(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||
public function unifyAccounts(UpdatedSingleTransactionGroup $updatedGroupEvent): void
|
||||
{
|
||||
Log::debug('Now in unifyAccounts()');
|
||||
$group = $updatedGroupEvent->transactionGroup;
|
||||
if (1 === $group->transactionJournals->count()) {
|
||||
Log::debug('Nothing to do in unifyAccounts()');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -142,14 +102,16 @@ class UpdatedGroupEventHandler
|
||||
// set all destination transactions to destination account:
|
||||
Transaction::whereIn('transaction_journal_id', $all)->where('amount', '>', 0)->update(['account_id' => $destAccount->id]);
|
||||
}
|
||||
Log::debug('Done with unifyAccounts()');
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will check all the rules when a journal is updated.
|
||||
*/
|
||||
private function processRules(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||
private function processRules(UpdatedSingleTransactionGroup $updatedGroupEvent): void
|
||||
{
|
||||
if (false === $updatedGroupEvent->applyRules) {
|
||||
Log::debug('Now in processRules()');
|
||||
if (false === $updatedGroupEvent->flags->applyRules) {
|
||||
Log::info(sprintf('Will not run rules on group #%d', $updatedGroupEvent->transactionGroup->id));
|
||||
|
||||
return;
|
||||
@@ -177,21 +139,24 @@ class UpdatedGroupEventHandler
|
||||
$newRuleEngine->addOperator(['type' => 'journal_id', 'value' => $journalIds]);
|
||||
$newRuleEngine->setRuleGroups($groups);
|
||||
$newRuleEngine->fire();
|
||||
Log::debug('Done with processRules()');
|
||||
}
|
||||
|
||||
private function recalculateCredit(UpdatedTransactionGroup $event): void
|
||||
private function recalculateCredit(UpdatedSingleTransactionGroup $event): void
|
||||
{
|
||||
Log::debug('Now in recalculateCredit()');
|
||||
$group = $event->transactionGroup;
|
||||
|
||||
/** @var CreditRecalculateService $object */
|
||||
$object = app(CreditRecalculateService::class);
|
||||
$object->setGroup($group);
|
||||
$object->recalculate();
|
||||
Log::debug('Done with recalculateCredit()');
|
||||
}
|
||||
|
||||
private function triggerWebhooks(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||
private function triggerWebhooks(UpdatedSingleTransactionGroup $updatedGroupEvent): void
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
Log::debug('Now in triggerWebhooks()');
|
||||
$group = $updatedGroupEvent->transactionGroup;
|
||||
if (false === $updatedGroupEvent->fireWebhooks) {
|
||||
Log::info(sprintf('Will not fire webhooks for transaction group #%d', $group->id));
|
||||
@@ -209,10 +174,12 @@ class UpdatedGroupEventHandler
|
||||
|
||||
Log::debug(sprintf('send event WebhookMessagesRequestSending from %s', __METHOD__));
|
||||
event(new WebhookMessagesRequestSending());
|
||||
Log::debug('End of triggerWebhooks()');
|
||||
}
|
||||
|
||||
private function updateRunningBalance(UpdatedTransactionGroup $event): void
|
||||
private function updateRunningBalance(UpdatedSingleTransactionGroup $event): void
|
||||
{
|
||||
Log::debug('Now in updateRunningBalance()');
|
||||
if (false === FireflyConfig::get('use_running_balance', config('firefly.feature_flags.running_balance_column'))->data) {
|
||||
return;
|
||||
}
|
||||
@@ -221,5 +188,6 @@ class UpdatedGroupEventHandler
|
||||
foreach ($group->transactionJournals as $journal) {
|
||||
AccountBalanceCalculator::recalculateForJournal($journal);
|
||||
}
|
||||
Log::debug('Done with updateRunningBalance()');
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Listeners\Security\System;
|
||||
|
||||
use Database\Seeders\ExchangeRateSeeder;
|
||||
use Exception;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Events\Security\System\NewUserRegistered;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
@@ -34,13 +33,13 @@ use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\User\UserRegistration as UserRegistrationNotification;
|
||||
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 implements ShouldQueue
|
||||
{
|
||||
@@ -117,24 +116,7 @@ class HandlesNewUserRegistration implements ShouldQueue
|
||||
if (!$sendMail) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Notification::send($owner, new AdminRegistrationNotification($user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($owner, new AdminRegistrationNotification($user));
|
||||
}
|
||||
|
||||
private function sendRegistrationMail(User $user): void
|
||||
@@ -144,22 +126,6 @@ class HandlesNewUserRegistration implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Notification::send($user, new UserRegistrationNotification());
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new UserRegistrationNotification());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ use FireflyIII\Mail\InvitationMail;
|
||||
use FireflyIII\Models\InvitedUser;
|
||||
use FireflyIII\Notifications\Admin\UserInvitation;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
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 NotifiesAboutNewInvitation implements ShouldQueue
|
||||
{
|
||||
@@ -68,22 +68,6 @@ class NotifiesAboutNewInvitation implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Notification::send(new OwnerNotifiable(), new UserInvitation($invitee));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send(new OwnerNotifiable(), new UserInvitation($invitee));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\System;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\System\SystemFoundNewVersionOnline;
|
||||
use FireflyIII\Notifications\Admin\VersionCheckResult;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesOwnerAboutNewVersion implements ShouldQueue
|
||||
{
|
||||
@@ -42,23 +40,7 @@ class NotifiesOwnerAboutNewVersion implements ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$owner = new OwnerNotifiable();
|
||||
Notification::send($owner, new VersionCheckResult($event->message));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
$owner = new OwnerNotifiable();
|
||||
NotificationSender::send($owner, new VersionCheckResult($event->message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,35 +24,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\System;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\System\UnknownUserTriedLogin;
|
||||
use FireflyIII\Notifications\Admin\UnknownUserLoginAttempt;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesOwnerAboutUnknownUser implements ShouldQueue
|
||||
{
|
||||
public function handle(UnknownUserTriedLogin $event): void
|
||||
{
|
||||
try {
|
||||
$owner = new OwnerNotifiable();
|
||||
Notification::send($owner, new UnknownUserLoginAttempt($event->address));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
$owner = new OwnerNotifiable();
|
||||
NotificationSender::send($owner, new UnknownUserLoginAttempt($event->address));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,37 +24,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasDisabledMFA;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\DisabledMFANotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutDisabledMFA implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasDisabledMFA $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new DisabledMFANotification($user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($event->user, new DisabledMFANotification($event->user));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasEnabledMFA;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\EnabledMFANotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutEnabledMFA implements ShouldQueue
|
||||
{
|
||||
@@ -38,23 +37,6 @@ class NotifiesUserAboutEnabledMFA implements ShouldQueue
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new EnabledMFANotification($user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new EnabledMFANotification($user));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,32 +24,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserFailedLoginAttempt;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\UserFailedLoginAttempt as NotificationFailedLoginAttempt;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutFailedLogin implements ShouldQueue
|
||||
{
|
||||
public function handle(UserFailedLoginAttempt $event): void
|
||||
{
|
||||
try {
|
||||
Notification::send($event->user, new \FireflyIII\Notifications\Security\UserFailedLoginAttempt($event->user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($event->user, new NotificationFailedLoginAttempt($event->user));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasFewMFABackupCodesLeft;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\MFABackupFewLeftNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutFewCodesLeft implements ShouldQueue
|
||||
{
|
||||
@@ -39,23 +38,6 @@ class NotifiesUserAboutFewCodesLeft implements ShouldQueue
|
||||
|
||||
$user = $event->user;
|
||||
$count = $event->count;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFABackupFewLeftNotification($user, $count));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new MFABackupFewLeftNotification($user, $count));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* NotifiesUserAboutNewAccessToken.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\Security\User;
|
||||
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\User\NewAccessToken;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Laravel\Passport\Events\AccessTokenCreated;
|
||||
|
||||
class NotifiesUserAboutNewAccessToken
|
||||
{
|
||||
public function handle(AccessTokenCreated $event): void
|
||||
{
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
$user = $repository->find((int) $event->userId);
|
||||
|
||||
if (null !== $user) {
|
||||
NotificationSender::send($user, new NewAccessToken());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,37 +24,18 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasGeneratedNewBackupCodes;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\NewBackupCodesNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutNewBackupCodes implements ShouldQueue
|
||||
{
|
||||
public function handle(UserHasGeneratedNewBackupCodes $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new NewBackupCodesNotification($user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new NewBackupCodesNotification($user));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserLoggedInFromNewIpAddress;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
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 implements ShouldQueue
|
||||
{
|
||||
@@ -50,23 +48,7 @@ class NotifiesUserAboutNewIpAddress implements ShouldQueue
|
||||
/** @var array $entry */
|
||||
foreach ($list as $index => $entry) {
|
||||
if (false === $entry['notified']) {
|
||||
try {
|
||||
Notification::send($user, new UserLogin());
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new UserLogin());
|
||||
}
|
||||
$list[$index]['notified'] = true;
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasNoMFABackupCodesLeft;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\MFABackupNoLeftNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutNoCodesLeft implements ShouldQueue
|
||||
{
|
||||
@@ -39,22 +38,6 @@ class NotifiesUserAboutNoCodesLeft implements ShouldQueue
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFABackupNoLeftNotification($user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new MFABackupNoLeftNotification($user));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserKeepsFailingMFA;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\MFAManyFailedAttemptsNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutRepeatedMFAFailures implements ShouldQueue
|
||||
{
|
||||
@@ -39,23 +38,6 @@ class NotifiesUserAboutRepeatedMFAFailures implements ShouldQueue
|
||||
|
||||
$user = $event->user;
|
||||
$count = $event->count;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFAManyFailedAttemptsNotification($user, $count));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new MFAManyFailedAttemptsNotification($user, $count));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserHasUsedBackupCode;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Security\MFAUsedBackupCodeNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifiesUserAboutUsedBackupCode implements ShouldQueue
|
||||
{
|
||||
@@ -38,23 +37,6 @@ class NotifiesUserAboutUsedBackupCode implements ShouldQueue
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$user = $event->user;
|
||||
|
||||
try {
|
||||
Notification::send($user, new MFAUsedBackupCodeNotification($user));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($user, new MFAUsedBackupCodeNotification($user));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,33 +24,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Security\User;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Security\User\UserRequestedNewPassword;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\User\UserNewPassword;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class SendsUserNewPassword implements ShouldQueue
|
||||
{
|
||||
public function handle(UserRequestedNewPassword $event): void
|
||||
{
|
||||
try {
|
||||
Notification::send($event->user, new UserNewPassword(route('password.reset', [$event->token])));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($event->user, new UserNewPassword(route('password.reset', [$event->token])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* PreferencesEventHandler.php
|
||||
* Copyright (c) 2024 james@firefly-iii.org.
|
||||
* RecalculatesPrimaryCurrencyAmounts.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -17,12 +19,10 @@
|
||||
* 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/.
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
namespace FireflyIII\Listeners\System;
|
||||
|
||||
use FireflyIII\Events\Preferences\UserGroupChangedPrimaryCurrency;
|
||||
use FireflyIII\Models\Budget;
|
||||
@@ -30,15 +30,15 @@ use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Recalculate\PrimaryAmountRecalculationService;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PreferencesEventHandler
|
||||
class RecalculatesPrimaryCurrencyAmounts
|
||||
{
|
||||
public function resetPrimaryCurrencyAmounts(UserGroupChangedPrimaryCurrency $event): void
|
||||
public function handle(UserGroupChangedPrimaryCurrency $event): void
|
||||
{
|
||||
// Reset the primary currency amounts for all objects that have it.
|
||||
Log::debug('Resetting primary currency amounts for all objects.');
|
||||
@@ -50,79 +50,67 @@ class PreferencesEventHandler
|
||||
'bills' => ['native_amount_min', 'native_amount_max'],
|
||||
];
|
||||
foreach ($tables as $table => $columns) {
|
||||
Log::debug(sprintf('Now processing table "%s"', $table));
|
||||
foreach ($columns as $column) {
|
||||
Log::debug(sprintf('Resetting column %s in table %s.', $column, $table));
|
||||
Log::debug(sprintf('Resetting column "%s" in table "%s".', $column, $table));
|
||||
DB::table($table)->where('user_group_id', $event->userGroup->id)->update([$column => null]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->resetPiggyBanks($event->userGroup);
|
||||
$this->resetBudgets($event->userGroup);
|
||||
$this->resetTransactions($event->userGroup);
|
||||
Log::debug('Have now reset all primary amounts to NULL.');
|
||||
// fire laravel command to recalculate them all.
|
||||
if (Amount::convertToPrimary()) {
|
||||
Log::debug('Will now convert to primary currency.');
|
||||
Artisan::call('correction:recalculate-pc-amounts');
|
||||
Log::debug('Will now convert amounts to primary currency.');
|
||||
|
||||
$calculator = new PrimaryAmountRecalculationService();
|
||||
$calculator->recalculate();
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug('Will NOT convert to primary currency.');
|
||||
}
|
||||
|
||||
private function resetPiggyBanks(UserGroup $userGroup): void
|
||||
private function resetBudget(Budget $budget): void
|
||||
{
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$piggyBanks = $repository->getPiggyBanks();
|
||||
Log::debug(sprintf('Resetting %d piggy bank(s).', $piggyBanks->count()));
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
if (null !== $piggyBank->native_target_amount) {
|
||||
Log::debug(sprintf('Resetting native_target_amount for piggy bank #%d.', $piggyBank->id));
|
||||
$piggyBank->native_target_amount = null;
|
||||
$piggyBank->saveQuietly();
|
||||
foreach ($budget->autoBudgets as $autoBudget) {
|
||||
if ('' === (string) $autoBudget->native_amount) {
|
||||
continue;
|
||||
}
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
if (null !== $account->pivot->native_current_amount) {
|
||||
Log::debug(sprintf('Resetting native_current_amount for piggy bank #%d and account #%d.', $piggyBank->id, $account->id));
|
||||
$account->pivot->native_current_amount = null;
|
||||
$account->pivot->save();
|
||||
}
|
||||
}
|
||||
foreach ($piggyBank->piggyBankEvents as $event) {
|
||||
if (null !== $event->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for piggy bank #%d and event #%d.', $piggyBank->id, $event->id));
|
||||
$event->native_amount = null;
|
||||
$event->saveQuietly();
|
||||
}
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and auto budget #%d.', $budget->id, $autoBudget->id));
|
||||
$autoBudget->native_amount = null;
|
||||
$autoBudget->saveQuietly();
|
||||
}
|
||||
foreach ($budget->budgetlimits as $limit) {
|
||||
if ('' !== (string) $limit->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and budget limit #%d.', $budget->id, $limit->id));
|
||||
$limit->native_amount = null;
|
||||
$limit->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function resetBudgets(UserGroup $userGroup): void
|
||||
private function resetPiggyBank(PiggyBank $piggyBank): void
|
||||
{
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getBudgets();
|
||||
|
||||
Log::debug(sprintf('Resetting %d budget(s).', $set->count()));
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
foreach ($budget->autoBudgets as $autoBudget) {
|
||||
if (null === $autoBudget->native_amount) {
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and auto budget #%d.', $budget->id, $autoBudget->id));
|
||||
$autoBudget->native_amount = null;
|
||||
$autoBudget->saveQuietly();
|
||||
if ('' !== (string) $piggyBank->native_target_amount) {
|
||||
Log::debug(sprintf('Resetting native_target_amount for piggy bank #%d.', $piggyBank->id));
|
||||
$piggyBank->native_target_amount = null;
|
||||
$piggyBank->saveQuietly();
|
||||
}
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
if ('' !== (string) $account->pivot->native_current_amount) {
|
||||
Log::debug(sprintf('Resetting native_current_amount for piggy bank #%d and account #%d.', $piggyBank->id, $account->id));
|
||||
$account->pivot->native_current_amount = null;
|
||||
$account->pivot->save();
|
||||
}
|
||||
foreach ($budget->budgetlimits as $limit) {
|
||||
if (null !== $limit->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for budget #%d and budget limit #%d.', $budget->id, $limit->id));
|
||||
$limit->native_amount = null;
|
||||
$limit->saveQuietly();
|
||||
}
|
||||
}
|
||||
foreach ($piggyBank->piggyBankEvents as $event) {
|
||||
if ('' !== (string) $event->native_amount) {
|
||||
Log::debug(sprintf('Resetting native_amount for piggy bank #%d and event #%d.', $piggyBank->id, $event->id));
|
||||
$event->native_amount = null;
|
||||
$event->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,10 +122,42 @@ class PreferencesEventHandler
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (Builder $q): void {
|
||||
$q->whereNotNull('native_amount')->orWhereNotNull('native_foreign_amount');
|
||||
$q
|
||||
->whereNotNull('native_amount')
|
||||
->orWhereNotNull('native_foreign_amount')
|
||||
->orWhere('native_amount', '!=', '')
|
||||
->orWhere('native_foreign_amount', '!=', '')
|
||||
;
|
||||
})
|
||||
->update(['native_amount' => null, 'native_foreign_amount' => null])
|
||||
;
|
||||
Log::debug(sprintf('Reset %d transactions.', $success));
|
||||
}
|
||||
|
||||
private function resetPiggyBanks(UserGroup $userGroup): void
|
||||
{
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$piggyBanks = $repository->getPiggyBanks();
|
||||
Log::debug(sprintf('Reset primary currency of %d piggy bank(s).', $piggyBanks->count()));
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
$this->resetPiggyBank($piggyBank);
|
||||
}
|
||||
}
|
||||
|
||||
private function resetBudgets(UserGroup $userGroup): void
|
||||
{
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getBudgets();
|
||||
|
||||
Log::debug(sprintf('Reset primary currency of %d budget(s).', $set->count()));
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$this->resetBudget($budget);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Listeners\Test;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Events\Test\OwnerTestsNotificationChannel;
|
||||
use FireflyIII\Events\Test\UserTestsNotificationChannel;
|
||||
use FireflyIII\Notifications\NotificationSender;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationEmail;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationPushover;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationSlack;
|
||||
@@ -34,7 +34,6 @@ use FireflyIII\Notifications\Test\UserTestNotificationEmail;
|
||||
use FireflyIII\Notifications\Test\UserTestNotificationPushover;
|
||||
use FireflyIII\Notifications\Test\UserTestNotificationSlack;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class SendsTestNotification
|
||||
{
|
||||
@@ -82,24 +81,7 @@ class SendsTestNotification
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Will send %s as a notification.', $class));
|
||||
|
||||
try {
|
||||
Notification::send($event->user, new $class());
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
NotificationSender::send($event->user, new $class());
|
||||
Log::debug(sprintf('If you see no errors above this line, test notification was sent over channel "%s"', $event->channel));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Handlers\Observer\AccountObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedAccountObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -42,7 +42,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[ObservedBy([AccountObserver::class])]
|
||||
#[ObservedBy([DeletedAccountObserver::class])]
|
||||
class Account extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AccountBalance.php
|
||||
* Copyright (c) 2025 james@firefly-iii.org.
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class AccountBalance extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['account_id', 'title', 'transaction_currency_id', 'balance', 'date', 'date_tz'];
|
||||
|
||||
public function account(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function transactionCurrency(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(TransactionCurrency::class);
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return ['date' => SeparateTimezoneCaster::class, 'balance' => 'string'];
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\AttachmentObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedAttachmentObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -36,7 +36,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[ObservedBy([AttachmentObserver::class])]
|
||||
#[ObservedBy([DeletedAttachmentObserver::class])]
|
||||
class Attachment extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\CategoryObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedCategoryObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -36,7 +36,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[ObservedBy([CategoryObserver::class])]
|
||||
#[ObservedBy([DeletedCategoryObserver::class])]
|
||||
class Category extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Handlers\Observer\RecurrenceObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedRecurrenceObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -43,7 +43,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property Carbon $first_date
|
||||
* @property null|Carbon $latest_date
|
||||
*/
|
||||
#[ObservedBy([RecurrenceObserver::class])]
|
||||
#[ObservedBy([DeletedRecurrenceObserver::class])]
|
||||
class Recurrence extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\RecurrenceTransactionObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedRecurrenceTransactionObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
@@ -33,7 +33,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
#[ObservedBy([RecurrenceTransactionObserver::class])]
|
||||
#[ObservedBy([DeletedRecurrenceTransactionObserver::class])]
|
||||
class RecurrenceTransaction extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\RuleObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedRuleObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -38,7 +38,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
/**
|
||||
* @property User $user
|
||||
*/
|
||||
#[ObservedBy([RuleObserver::class])]
|
||||
#[ObservedBy([DeletedRuleObserver::class])]
|
||||
class Rule extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\RuleGroupObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedRuleGroupObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -40,7 +40,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property User $user
|
||||
* @property Collection $rules
|
||||
*/
|
||||
#[ObservedBy([RuleGroupObserver::class])]
|
||||
#[ObservedBy([DeletedRuleGroupObserver::class])]
|
||||
class RuleGroup extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Handlers\Observer\TagObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedTagObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -36,7 +36,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[ObservedBy([TagObserver::class])]
|
||||
#[ObservedBy([DeletedTagObserver::class])]
|
||||
class Tag extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\TransactionGroupObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedTransactionGroupObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -41,7 +41,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property UserGroup $userGroup
|
||||
* @property Collection<TransactionJournal> $transactionJournals
|
||||
*/
|
||||
#[ObservedBy([TransactionGroupObserver::class])]
|
||||
#[ObservedBy([DeletedTransactionGroupObserver::class])]
|
||||
class TransactionGroup extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace FireflyIII\Models;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Casts\SeparateTimezoneCaster;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Handlers\Observer\TransactionJournalObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedTransactionJournalObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -50,7 +50,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
*
|
||||
* @property TransactionGroup $transactionGroup
|
||||
*/
|
||||
#[ObservedBy([TransactionJournalObserver::class])]
|
||||
#[ObservedBy([DeletedTransactionJournalObserver::class])]
|
||||
class TransactionJournal extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FireflyIII\Models;
|
||||
use FireflyIII\Enums\WebhookDelivery as WebhookDeliveryEnum;
|
||||
use FireflyIII\Enums\WebhookResponse as WebhookResponseEnum;
|
||||
use FireflyIII\Enums\WebhookTrigger as WebhookTriggerEnum;
|
||||
use FireflyIII\Handlers\Observer\WebhookObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedWebhookObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
|
||||
use FireflyIII\User;
|
||||
@@ -39,7 +39,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[ObservedBy([WebhookObserver::class])]
|
||||
#[ObservedBy([DeletedWebhookObserver::class])]
|
||||
class Webhook extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Handlers\Observer\WebhookMessageObserver;
|
||||
use FireflyIII\Handlers\Observer\DeletedWebhookMessageObserver;
|
||||
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
@@ -34,7 +34,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
#[ObservedBy([WebhookMessageObserver::class])]
|
||||
#[ObservedBy([DeletedWebhookMessageObserver::class])]
|
||||
class WebhookMessage extends Model
|
||||
{
|
||||
use ReturnsIntegerIdTrait;
|
||||
|
||||
59
app/Notifications/NotificationSender.php
Normal file
59
app/Notifications/NotificationSender.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* NotificationSender.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\Notifications;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\User;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification as NotificationFacade;
|
||||
|
||||
class NotificationSender
|
||||
{
|
||||
public static function send(OwnerNotifiable|User $user, Notification $notification): void
|
||||
{
|
||||
try {
|
||||
NotificationFacade::send($user, $notification);
|
||||
} catch (ClientException $e) {
|
||||
Log::error(sprintf('[a] Error sending notification: %s', $e->getMessage()));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AccountPolicy.php
|
||||
* Copyright (c) 2024 james@firefly-iii.org.
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Policies;
|
||||
|
||||
use FireflyIII\Entities\AccountBalance;
|
||||
use FireflyIII\User;
|
||||
|
||||
class AccountBalancePolicy
|
||||
{
|
||||
/**
|
||||
* TODO needs better authentication.
|
||||
*/
|
||||
public function view(User $user, AccountBalance $accountBalance): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Everybody can do this, but selection should limit to user.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function viewAny(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -262,6 +262,12 @@ class JournalRepository implements JournalRepositoryInterface, UserGroupInterfac
|
||||
;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getAllUncompletedJournals(): Collection
|
||||
{
|
||||
return TransactionJournal::where('completed', false)->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function markAsCompleted(Collection $set): void
|
||||
{
|
||||
|
||||
@@ -54,6 +54,8 @@ interface JournalRepositoryInterface
|
||||
|
||||
public function getUncompletedJournals(): Collection;
|
||||
|
||||
public function getAllUncompletedJournals(): Collection;
|
||||
|
||||
public function markAsCompleted(Collection $set): void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,7 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
use function Safe\json_decode;
|
||||
use function Safe\json_encode;
|
||||
@@ -594,4 +595,14 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function setLatestDate(Recurrence $recurrence, ?Carbon $date): Recurrence
|
||||
{
|
||||
$recurrence->latest_date = $date;
|
||||
$recurrence->latest_date_tz = $date?->format('e');
|
||||
$recurrence->save();
|
||||
|
||||
return $recurrence;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface RecurringRepositoryInterface
|
||||
{
|
||||
public function setLatestDate(Recurrence $recurrence, Carbon $date): Recurrence;
|
||||
|
||||
public function createdPreviously(Recurrence $recurrence, Carbon $date): bool;
|
||||
|
||||
/**
|
||||
|
||||
35
app/Services/Internal/Destroy/GenericDestroyService.php
Normal file
35
app/Services/Internal/Destroy/GenericDestroyService.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* GenericDestroyService.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\Services\Internal\Destroy;
|
||||
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
|
||||
class GenericDestroyService
|
||||
{
|
||||
public function deleteRuleTrigger(RuleTrigger $ruleTrigger): void
|
||||
{
|
||||
$ruleTrigger->forceDelete();
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Services\Internal\Destroy;
|
||||
|
||||
use FireflyIII\Events\DestroyedTransactionGroup;
|
||||
use FireflyIII\Events\Model\TransactionGroup\DestroyedSingleTransactionGroup;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -44,6 +44,6 @@ class TransactionGroupDestroyService
|
||||
}
|
||||
$transactionGroup->delete();
|
||||
// trigger just after destruction
|
||||
event(new DestroyedTransactionGroup($transactionGroup));
|
||||
event(new DestroyedSingleTransactionGroup($transactionGroup));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* RecalculatesPrimaryAmounts.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\Services\Internal\Recalculate;
|
||||
|
||||
use FireflyIII\Handlers\Observer\TransactionObserver;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder as DatabaseBuilder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PrimaryAmountRecalculationService
|
||||
{
|
||||
public function recalculate(): void
|
||||
{
|
||||
if (false === FireflyConfig::get('enable_exchange_rates', config('cer.enabled'))->data) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var UserGroupRepositoryInterface $repository */
|
||||
$repository = app(UserGroupRepositoryInterface::class);
|
||||
Preferences::mark();
|
||||
|
||||
/** @var UserGroup $userGroup */
|
||||
foreach ($repository->getAll() as $userGroup) {
|
||||
$this->recalculateForGroup($userGroup);
|
||||
}
|
||||
}
|
||||
|
||||
private function recalculateForGroup(UserGroup $userGroup): void
|
||||
{
|
||||
Log::debug(sprintf('Now recalculating primary amounts for user group #%d', $userGroup->id));
|
||||
$this->recalculateAccounts($userGroup);
|
||||
|
||||
// do a check with the group's currency so we can skip some stuff.
|
||||
$currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
|
||||
|
||||
$this->recalculatePiggyBanks($userGroup, $currency);
|
||||
$this->recalculateBudgets($userGroup, $currency);
|
||||
$this->recalculateAvailableBudgets($userGroup, $currency);
|
||||
$this->recalculateBills($userGroup, $currency);
|
||||
$this->calculateTransactions($userGroup, $currency);
|
||||
}
|
||||
|
||||
private function recalculateAccounts(UserGroup $userGroup): void
|
||||
{
|
||||
$set = $userGroup
|
||||
->accounts()
|
||||
->where(static function (EloquentBuilder $q): void {
|
||||
$q->whereNotNull('virtual_balance');
|
||||
|
||||
// this needs a different piece of code for postgres.
|
||||
if ('pgsql' === config('database.default')) {
|
||||
$q->orWhere(DB::raw('CAST(virtual_balance AS TEXT)'), '!=', '');
|
||||
}
|
||||
if ('pgsql' !== config('database.default')) {
|
||||
$q->orWhere('virtual_balance', '!=', '');
|
||||
}
|
||||
})
|
||||
->get()
|
||||
;
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($set as $account) {
|
||||
$account->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d accounts for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
private function recalculatePiggyBanks(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$converter = new ExchangeRateConverter();
|
||||
$converter->setUserGroup($userGroup);
|
||||
$converter->setIgnoreSettings(true);
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getPiggyBanks();
|
||||
$set = $set->filter(static fn (PiggyBank $piggyBank): bool => $currency->id !== $piggyBank->transaction_currency_id);
|
||||
foreach ($set as $piggyBank) {
|
||||
$piggyBank->encrypted = false;
|
||||
$piggyBank->save();
|
||||
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
$account->pivot->native_current_amount = null;
|
||||
if (0 !== bccomp((string) $account->pivot->current_amount, '0')) {
|
||||
$account->pivot->native_current_amount = $converter->convert(
|
||||
$piggyBank->transactionCurrency,
|
||||
$currency,
|
||||
today(),
|
||||
(string) $account->pivot->current_amount
|
||||
);
|
||||
}
|
||||
$account->pivot->save();
|
||||
}
|
||||
$this->recalculatePiggyBankEvents($piggyBank);
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d piggy banks for user group #%d.', $set->count(), $userGroup->id));
|
||||
}
|
||||
|
||||
private function recalculatePiggyBankEvents(PiggyBank $piggyBank): void
|
||||
{
|
||||
$set = $piggyBank->piggyBankEvents()->get();
|
||||
$set->each(static function (PiggyBankEvent $event): void { // @phpstan-ignore-line
|
||||
$event->touch();
|
||||
});
|
||||
Log::debug(sprintf('Recalculated %d piggy bank events.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateBudgets(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $userGroup->budgets()->get();
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$this->recalculateBudgetLimits($budget, $currency);
|
||||
$this->recalculateAutoBudgets($budget, $currency);
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d budgets.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateBudgetLimits(Budget $budget, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $budget->budgetlimits()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($set as $limit) {
|
||||
Log::debug(sprintf('Will now touch BL #%d', $limit->id));
|
||||
$limit->touch();
|
||||
Log::debug(sprintf('Done with touch BL #%d', $limit->id));
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d budget limits for budget #%d.', $set->count(), $budget->id));
|
||||
}
|
||||
|
||||
private function recalculateAutoBudgets(Budget $budget, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $budget->autoBudgets()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var AutoBudget $autoBudget */
|
||||
foreach ($set as $autoBudget) {
|
||||
$autoBudget->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d auto budgets for budget #%d.', $set->count(), $budget->id));
|
||||
}
|
||||
|
||||
private function recalculateAvailableBudgets(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
Log::debug('Start with available budgets.');
|
||||
$set = $userGroup->availableBudgets()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var AvailableBudget $budget */
|
||||
foreach ($set as $budget) {
|
||||
$budget->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d available budgets.', $set->count()));
|
||||
}
|
||||
|
||||
private function recalculateBills(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
$set = $userGroup->bills()->where('transaction_currency_id', '!=', $currency->id)->get();
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($set as $bill) {
|
||||
$bill->touch();
|
||||
}
|
||||
Log::debug(sprintf('Recalculated %d bills.', $set->count()));
|
||||
}
|
||||
|
||||
private function calculateTransactions(UserGroup $userGroup, TransactionCurrency $currency): void
|
||||
{
|
||||
// custom query because of the potential size of this update.
|
||||
$set = DB::table('transactions')
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (DatabaseBuilder $q1) use ($currency): void {
|
||||
$q1->where(static function (DatabaseBuilder $q2) use ($currency): void {
|
||||
$q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');
|
||||
})->orWhere(static function (DatabaseBuilder $q3) use ($currency): void {
|
||||
$q3->whereNot('transactions.transaction_currency_id', $currency->id)->whereNot('transactions.foreign_currency_id', $currency->id);
|
||||
});
|
||||
})
|
||||
// ->where(static function (DatabaseBuilder $q) use ($currency): void {
|
||||
// $q->whereNot('transactions.transaction_currency_id', $currency->id)
|
||||
// ->whereNot('transactions.foreign_currency_id', $currency->id)
|
||||
// ;
|
||||
// })
|
||||
->get(['transactions.id'])
|
||||
;
|
||||
TransactionObserver::$recalculate = false;
|
||||
foreach ($set as $item) {
|
||||
// here we are.
|
||||
/** @var null|Transaction $transaction */
|
||||
$transaction = Transaction::find($item->id);
|
||||
$transaction?->touch();
|
||||
}
|
||||
TransactionObserver::$recalculate = true;
|
||||
Log::debug(sprintf('Recalculated %d transactions.', $set->count()));
|
||||
}
|
||||
}
|
||||
@@ -25,12 +25,8 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Support\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountBalance;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -57,8 +53,9 @@ class AccountBalanceCalculator
|
||||
{
|
||||
if ($forced) {
|
||||
Transaction::whereNull('deleted_at')->update(['balance_dirty' => true]);
|
||||
|
||||
// also delete account balances.
|
||||
AccountBalance::whereNotNull('created_at')->delete();
|
||||
// AccountBalance::whereNotNull('created_at')->delete();
|
||||
}
|
||||
$object = new self();
|
||||
self::optimizedCalculation(new Collection());
|
||||
@@ -215,51 +212,4 @@ class AccountBalanceCalculator
|
||||
// save all collected balances in their respective account objects.
|
||||
// $this->storeAccountBalances($balances);
|
||||
}
|
||||
|
||||
private function storeAccountBalances(array $balances): void
|
||||
{
|
||||
/**
|
||||
* @var int $accountId
|
||||
* @var array $currencies
|
||||
*/
|
||||
foreach ($balances as $accountId => $currencies) {
|
||||
/** @var null|Account $account */
|
||||
$account = Account::find($accountId);
|
||||
if (null === $account) {
|
||||
Log::error(sprintf('Could not find account #%d, will not save account balance.', $accountId));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int $currencyId
|
||||
* @var array $balance
|
||||
*/
|
||||
foreach ($currencies as $currencyId => $balance) {
|
||||
try {
|
||||
$currency = Amount::getTransactionCurrencyById($currencyId);
|
||||
} catch (FireflyException) {
|
||||
Log::error(sprintf('Could not find currency #%d, will not save account balance.', $currencyId));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var AccountBalance $object */
|
||||
$object = $account
|
||||
->accountBalances()
|
||||
->firstOrCreate([
|
||||
'title' => 'running_balance',
|
||||
'balance' => '0',
|
||||
'transaction_currency_id' => $currencyId,
|
||||
'date' => $balance[1],
|
||||
'date_tz' => $balance[1]?->format('e'),
|
||||
])
|
||||
;
|
||||
$object->balance = $balance[0];
|
||||
$object->date = $balance[1];
|
||||
$object->date_tz = $balance[1]?->format('e');
|
||||
$object->saveQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,9 @@
|
||||
"composer/package-versions-deprecated": true,
|
||||
"phpstan/extension-installer": true,
|
||||
"php-http/discovery": true
|
||||
},
|
||||
"platform": {
|
||||
"php": "8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
81
composer.lock
generated
81
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1de93b568d1a9a4847285e5b5bc6695b",
|
||||
"content-hash": "72404106289a876b0046dceacbaccf24",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@@ -130,16 +130,16 @@
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.14.3",
|
||||
"version": "0.14.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "6af96b11de3f7d99730c118c200418c48274edb4"
|
||||
"reference": "618a8077b3c326045e10d5788ed713b341fcfe40"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/6af96b11de3f7d99730c118c200418c48274edb4",
|
||||
"reference": "6af96b11de3f7d99730c118c200418c48274edb4",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/618a8077b3c326045e10d5788ed713b341fcfe40",
|
||||
"reference": "618a8077b3c326045e10d5788ed713b341fcfe40",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -178,7 +178,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.14.3"
|
||||
"source": "https://github.com/brick/math/tree/0.14.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -186,7 +186,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-01T15:18:05+00:00"
|
||||
"time": "2026-02-03T18:06:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
@@ -3894,16 +3894,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.1.1",
|
||||
"version": "v4.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "c99059c0315591f1a0db7ad6002000288ab8dc72"
|
||||
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72",
|
||||
"reference": "c99059c0315591f1a0db7ad6002000288ab8dc72",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
|
||||
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3916,7 +3916,7 @@
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "^1.2",
|
||||
"nette/tester": "^2.5",
|
||||
"phpstan/phpstan-nette": "^2.0@stable",
|
||||
"phpstan/phpstan": "^2.0@stable",
|
||||
"tracy/tracy": "^2.9"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -3977,9 +3977,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.1"
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.2"
|
||||
},
|
||||
"time": "2025-12-22T12:14:32+00:00"
|
||||
"time": "2026-02-03T17:21:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
@@ -10683,16 +10683,16 @@
|
||||
},
|
||||
{
|
||||
"name": "iamcal/sql-parser",
|
||||
"version": "v0.6",
|
||||
"version": "v0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/iamcal/SQLParser.git",
|
||||
"reference": "947083e2dca211a6f12fb1beb67a01e387de9b62"
|
||||
"reference": "610392f38de49a44dab08dc1659960a29874c4b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/iamcal/SQLParser/zipball/947083e2dca211a6f12fb1beb67a01e387de9b62",
|
||||
"reference": "947083e2dca211a6f12fb1beb67a01e387de9b62",
|
||||
"url": "https://api.github.com/repos/iamcal/SQLParser/zipball/610392f38de49a44dab08dc1659960a29874c4b8",
|
||||
"reference": "610392f38de49a44dab08dc1659960a29874c4b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -10718,27 +10718,27 @@
|
||||
"description": "MySQL schema parser",
|
||||
"support": {
|
||||
"issues": "https://github.com/iamcal/SQLParser/issues",
|
||||
"source": "https://github.com/iamcal/SQLParser/tree/v0.6"
|
||||
"source": "https://github.com/iamcal/SQLParser/tree/v0.7"
|
||||
},
|
||||
"time": "2025-03-17T16:59:46+00:00"
|
||||
"time": "2026-01-28T22:20:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "larastan/larastan",
|
||||
"version": "v3.9.1",
|
||||
"version": "v3.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/larastan/larastan.git",
|
||||
"reference": "4b92d9627f779fd32bdc16f53f8ce88c50446ff5"
|
||||
"reference": "2e9ed291bdc1969e7f270fb33c9cdf3c912daeb2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/larastan/larastan/zipball/4b92d9627f779fd32bdc16f53f8ce88c50446ff5",
|
||||
"reference": "4b92d9627f779fd32bdc16f53f8ce88c50446ff5",
|
||||
"url": "https://api.github.com/repos/larastan/larastan/zipball/2e9ed291bdc1969e7f270fb33c9cdf3c912daeb2",
|
||||
"reference": "2e9ed291bdc1969e7f270fb33c9cdf3c912daeb2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"iamcal/sql-parser": "^0.6.0",
|
||||
"iamcal/sql-parser": "^0.7.0",
|
||||
"illuminate/console": "^11.44.2 || ^12.4.1",
|
||||
"illuminate/container": "^11.44.2 || ^12.4.1",
|
||||
"illuminate/contracts": "^11.44.2 || ^12.4.1",
|
||||
@@ -10802,7 +10802,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/larastan/larastan/issues",
|
||||
"source": "https://github.com/larastan/larastan/tree/v3.9.1"
|
||||
"source": "https://github.com/larastan/larastan/tree/v3.9.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10810,7 +10810,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-21T09:15:17+00:00"
|
||||
"time": "2026-01-30T15:16:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel-json-api/testing",
|
||||
@@ -11651,16 +11651,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "6.0.0",
|
||||
"version": "6.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "961bc913d42fe24a257bfff826a5068079ac7782"
|
||||
"reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782",
|
||||
"reference": "961bc913d42fe24a257bfff826a5068079ac7782",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5",
|
||||
"reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11700,15 +11700,27 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0"
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-07T04:58:37+00:00"
|
||||
"time": "2026-02-02T14:04:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-invoker",
|
||||
@@ -13199,5 +13211,8 @@
|
||||
"ext-xmlwriter": "*"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"platform-overrides": {
|
||||
"php": "8.4"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => (bool)envNonEmpty('USE_RUNNING_BALANCE', true), // this is only the default value, is not used.
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2026-02-02',
|
||||
'build_time' => 1770004409,
|
||||
'version' => 'develop/2026-02-04',
|
||||
'build_time' => 1770187668,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 28, // field is no longer used.
|
||||
|
||||
|
||||
14
mago.toml
14
mago.toml
@@ -41,3 +41,17 @@ strict-list-index-checks = false
|
||||
no-boolean-literal-comparison = false
|
||||
check-missing-type-hints = false
|
||||
register-super-globals = true
|
||||
|
||||
# deze mag iedereen
|
||||
[[guard.perimeter.rules]]
|
||||
namespace = "FireflyIII\\"
|
||||
permit = ["Carbon\\Carbon"]
|
||||
|
||||
# guard rules
|
||||
[[guard.perimeter.rules]]
|
||||
namespace = "FireflyIII\\Services"
|
||||
permit = ["@self", "@native","FireflyIII\\Models"]
|
||||
|
||||
[[guard.perimeter.rules]]
|
||||
namespace = "FireflyIII\\Transformers"
|
||||
permit = ["@self", "@native","FireflyIII\\Models"]
|
||||
|
||||
44
package-lock.json
generated
44
package-lock.json
generated
@@ -3848,9 +3848,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/alpinejs": {
|
||||
"version": "3.15.6",
|
||||
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.6.tgz",
|
||||
"integrity": "sha512-ETE0k88xU74URryk2JyvmrvyCyZG0Wo+2/tZux9gEvaPc/k5XcBSdvFHyW76puIFqhD+nHgeO/5j3pRRsHh6HA==",
|
||||
"version": "3.15.8",
|
||||
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.8.tgz",
|
||||
"integrity": "sha512-zxIfCRTBGvF1CCLIOMQOxAyBuqibxSEwS6Jm1a3HGA9rgrJVcjEWlwLcQTVGAWGS8YhAsTRLVrtQ5a5QT9bSSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "~3.1.1"
|
||||
@@ -4578,9 +4578,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001766",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
|
||||
"integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
|
||||
"version": "1.0.30001767",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz",
|
||||
"integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -5783,9 +5783,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.283",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz",
|
||||
"integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==",
|
||||
"version": "1.5.286",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
|
||||
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -5840,14 +5840,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.4",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
|
||||
"integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
|
||||
"version": "5.19.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
|
||||
"integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
"tapable": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
@@ -6645,7 +6645,7 @@
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -7118,9 +7118,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "25.8.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.0.tgz",
|
||||
"integrity": "sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==",
|
||||
"version": "25.8.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.1.tgz",
|
||||
"integrity": "sha512-nFFxhwcRNggIrkv2hx/xMYVMG7Z8iMUA4ZuH4tgcbZiI0bK1jn3kSDIXNWuQDt1xVAu7mb7Qn82TpH7ZAk/okA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -11801,9 +11801,9 @@
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.104.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
|
||||
"integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
|
||||
"version": "5.105.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
|
||||
"integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -11817,7 +11817,7 @@
|
||||
"acorn-import-phases": "^1.0.3",
|
||||
"browserslist": "^4.28.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.17.4",
|
||||
"enhanced-resolve": "^5.19.0",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
@@ -11830,7 +11830,7 @@
|
||||
"schema-utils": "^4.3.3",
|
||||
"tapable": "^2.3.0",
|
||||
"terser-webpack-plugin": "^5.3.16",
|
||||
"watchpack": "^2.4.4",
|
||||
"watchpack": "^2.5.1",
|
||||
"webpack-sources": "^3.3.3"
|
||||
},
|
||||
"bin": {
|
||||
|
||||
@@ -78,10 +78,10 @@ export default class Get {
|
||||
/**
|
||||
*
|
||||
* @param identifier
|
||||
* @param page
|
||||
* @param params
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
transactions(identifier, page) {
|
||||
return api.get('/api/v1/accounts/' + identifier + '/transactions', {params: {page: page}});
|
||||
transactions(identifier, params) {
|
||||
return api.get('/api/v1/accounts/' + identifier + '/transactions', {params: params});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user