mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-11-07 18:37:55 +00:00
Compare commits
23 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c195dcc66 | ||
|
|
0b45506e52 | ||
|
|
51e58f8d88 | ||
|
|
d0c658e79a | ||
|
|
35e0791a9f | ||
|
|
637ecc66d2 | ||
|
|
3a38175b2a | ||
|
|
d78fd86d7a | ||
|
|
395332d6dd | ||
|
|
c5cbceb81a | ||
|
|
ec94f1bcf1 | ||
|
|
ee3d18a8ea | ||
|
|
a9cd8b6512 | ||
|
|
5bd87036b0 | ||
|
|
0e7d72023d | ||
|
|
314f91ff24 | ||
|
|
ed54a5c9a4 | ||
|
|
5d35edb126 | ||
|
|
8bdfdc39cb | ||
|
|
d465b51da8 | ||
|
|
3344d2e5f3 | ||
|
|
0521da124e | ||
|
|
7e9c5a668f |
@@ -72,21 +72,24 @@ class UpdateController extends Controller
|
||||
public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse
|
||||
{
|
||||
app('log')->debug('Now in update routine for transaction group');
|
||||
$data = $request->getAll();
|
||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||
$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();
|
||||
|
||||
app('preferences')->mark();
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
$runRecalculations = $oldHash !== $newHash;
|
||||
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $runRecalculations));
|
||||
|
||||
/** @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.
|
||||
@@ -95,20 +98,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);
|
||||
}
|
||||
|
||||
@@ -65,28 +65,29 @@ class UpdateController extends Controller
|
||||
public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse
|
||||
{
|
||||
app('log')->debug('Now in update routine for transaction group [v2]!');
|
||||
$data = $request->getAll();
|
||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
$data = $request->getAll();
|
||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
$runRecalculations = true;
|
||||
|
||||
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
|
||||
event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $runRecalculations));
|
||||
app('preferences')->mark();
|
||||
|
||||
/** @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)->setTransactionGroup($transactionGroup);
|
||||
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
if (null === $selectedGroup) {
|
||||
throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
|
||||
}
|
||||
|
||||
$transformer = new TransactionGroupTransformer();
|
||||
$transformer = new TransactionGroupTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()->api($this->jsonApiObject('transactions', $selectedGroup, $transformer))->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
||||
@@ -58,7 +58,8 @@ class CorrectsGroupAccounts extends Command
|
||||
$handler = new UpdatedGroupEventHandler();
|
||||
foreach ($groups as $groupId) {
|
||||
$group = TransactionGroup::find($groupId);
|
||||
$event = new UpdatedTransactionGroup($group, true, true);
|
||||
// TODO in theory the "unifyAccounts" method could lead to the need for run recalculations.
|
||||
$event = new UpdatedTransactionGroup($group, true, true, false);
|
||||
$handler->unifyAccounts($event);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class CorrectsIbans extends Command
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$accounts = Account::whereNotNull('iban')->get();
|
||||
$accounts = Account::with('accountMeta')->get();
|
||||
$this->filterIbans($accounts);
|
||||
$this->countAndCorrectIbans($accounts);
|
||||
|
||||
@@ -54,14 +54,26 @@ class CorrectsIbans extends Command
|
||||
{
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$iban = (string) $account->iban;
|
||||
$newIban = app('steam')->filterSpaces($iban);
|
||||
$iban = (string) $account->iban;
|
||||
$newIban = app('steam')->filterSpaces($iban);
|
||||
if ('' !== $iban && $iban !== $newIban) {
|
||||
$account->iban = $newIban;
|
||||
$account->save();
|
||||
$this->friendlyInfo(sprintf('Removed spaces from IBAN of account #%d', $account->id));
|
||||
++$this->count;
|
||||
}
|
||||
// same for account number:
|
||||
$accountNumber = $account->accountMeta->where('name', 'account_number')->first();
|
||||
if (null !== $accountNumber) {
|
||||
$number = (string) $accountNumber->value;
|
||||
$newNumber = app('steam')->filterSpaces($number);
|
||||
if ('' !== $number && $number !== $newNumber) {
|
||||
$accountNumber->value = $newNumber;
|
||||
$accountNumber->save();
|
||||
$this->friendlyInfo(sprintf('Removed spaces from account number of account #%d', $account->id));
|
||||
++$this->count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
16
app/Events/Model/PiggyBank/ChangedName.php
Normal file
16
app/Events/Model/PiggyBank/ChangedName.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events\Model\PiggyBank;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ChangedName extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(public PiggyBank $piggyBank, public string $oldName, public string $newName) {}
|
||||
}
|
||||
@@ -37,5 +37,5 @@ class UpdatedTransactionGroup extends Event
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(public TransactionGroup $transactionGroup, public bool $applyRules, public bool $fireWebhooks) {}
|
||||
public function __construct(public TransactionGroup $transactionGroup, public bool $applyRules, public bool $fireWebhooks, public bool $runRecalculations) {}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
|
||||
/**
|
||||
* Class AccountMetaFactory
|
||||
@@ -41,11 +42,16 @@ class AccountMetaFactory
|
||||
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||
// must not be an empty string:
|
||||
if ('' !== $value) {
|
||||
if ('account_number' === $field) {
|
||||
$value = Steam::filterSpaces($value);
|
||||
$value = trim(str_replace([' ', "\t", "\n", "\r"], '', $value));
|
||||
}
|
||||
// if $data has field and $entry is null, create new one:
|
||||
if (null === $entry) {
|
||||
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
|
||||
}
|
||||
|
||||
|
||||
// if $data has field and $entry is not null, update $entry:
|
||||
$entry->data = $value;
|
||||
$entry->save();
|
||||
|
||||
@@ -24,6 +24,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events\Model;
|
||||
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedName;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
@@ -33,6 +37,24 @@ use FireflyIII\Models\PiggyBankEvent;
|
||||
*/
|
||||
class PiggyBankEventHandler
|
||||
{
|
||||
public function changedPiggyBankName(ChangedName $event): void
|
||||
{
|
||||
// loop all accounts, collect all user's rules.
|
||||
/** @var Account $account */
|
||||
foreach ($event->piggyBank->accounts as $account) {
|
||||
/** @var Rule $rule */
|
||||
foreach ($account->user->rules as $rule) {
|
||||
/** @var RuleAction $ruleAction */
|
||||
foreach ($rule->ruleActions()->where('action_type', 'update_piggy')->get() as $ruleAction) {
|
||||
if ($event->oldName === $ruleAction->action_value) {
|
||||
$ruleAction->action_value = $event->newName;
|
||||
$ruleAction->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function changePiggyAmount(ChangedAmount $event): void
|
||||
{
|
||||
// find journal if group is present.
|
||||
|
||||
@@ -49,7 +49,9 @@ class UpdatedGroupEventHandler
|
||||
$this->processRules($event);
|
||||
$this->recalculateCredit($event);
|
||||
$this->triggerWebhooks($event);
|
||||
$this->updateRunningBalance($event);
|
||||
if ($event->runRecalculations) {
|
||||
$this->updateRunningBalance($event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$this->hasJoinedAttTables = false;
|
||||
$this->expandGroupSearch = false;
|
||||
$this->hasJoinedMetaTables = false;
|
||||
$this->booleanFields = ['balance_dirty'];
|
||||
$this->booleanFields = ['source_balance_dirty', 'destination_balance_dirty'];
|
||||
$this->integerFields = [
|
||||
'transaction_group_id',
|
||||
'user_id',
|
||||
@@ -137,7 +137,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// currency info:
|
||||
'source.amount as amount',
|
||||
'source.balance_after as source_balance_after',
|
||||
'source.balance_dirty as balance_dirty',
|
||||
'source.balance_dirty as source_balance_dirty',
|
||||
'source.native_amount as native_amount',
|
||||
'source.transaction_currency_id as currency_id',
|
||||
'currency.code as currency_code',
|
||||
@@ -157,6 +157,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// destination account info (always present)
|
||||
'destination.account_id as destination_account_id',
|
||||
'destination.balance_after as destination_balance_after',
|
||||
'destination.balance_dirty as destination_balance_dirty',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -75,13 +75,22 @@ class AmountController extends Controller
|
||||
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
|
||||
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
|
||||
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
|
||||
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
|
||||
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
|
||||
|
||||
Log::debug(sprintf(
|
||||
'Account "%s", left on account "%s", saved so far "%s", left to save "%s", max amount "%s".',
|
||||
$account->name,
|
||||
$leftOnAccount,
|
||||
$totalSaved,
|
||||
$leftToSave,
|
||||
$maxAmount,
|
||||
));
|
||||
|
||||
$accounts[] = [
|
||||
'account' => $account,
|
||||
'left_on_account' => $leftOnAccount,
|
||||
'saved_so_far' => $savedSoFar,
|
||||
'total_saved' => $totalSaved,
|
||||
'left_to_save' => $leftToSave,
|
||||
'max_amount' => $maxAmount,
|
||||
];
|
||||
@@ -100,18 +109,18 @@ class AmountController extends Controller
|
||||
public function addMobile(PiggyBank $piggyBank)
|
||||
{
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', today(config('app.timezone')));
|
||||
$accounts = [];
|
||||
$total = '0';
|
||||
$date = session('end', today(config('app.timezone')));
|
||||
$accounts = [];
|
||||
$total = '0';
|
||||
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
|
||||
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
|
||||
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
|
||||
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
|
||||
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
|
||||
$accounts[] = [
|
||||
'account' => $account,
|
||||
'left_on_account' => $leftOnAccount,
|
||||
'saved_so_far' => $savedSoFar,
|
||||
'total_saved' => $totalSaved,
|
||||
'left_to_save' => $leftToSave,
|
||||
'max_amount' => $maxAmount,
|
||||
];
|
||||
|
||||
@@ -63,6 +63,14 @@ class EditController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
public function resetHistory(PiggyBank $piggyBank): RedirectResponse
|
||||
{
|
||||
$this->piggyRepos->resetHistory($piggyBank);
|
||||
session()->flash('success', (string) trans('firefly.piggy_history_reset'));
|
||||
|
||||
return redirect(route('piggy-banks.show', [$piggyBank->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a piggy bank.
|
||||
*
|
||||
|
||||
@@ -118,7 +118,7 @@ class BulkController extends Controller
|
||||
// run rules on changed journals:
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($collection as $journal) {
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true));
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, false));
|
||||
}
|
||||
|
||||
app('preferences')->mark();
|
||||
|
||||
@@ -292,7 +292,7 @@ class ConvertController extends Controller
|
||||
$group->refresh();
|
||||
|
||||
session()->flash('success', (string) trans('firefly.converted_to_'.$destinationType->type));
|
||||
event(new UpdatedTransactionGroup($group, true, true));
|
||||
event(new UpdatedTransactionGroup($group, true, true, true));
|
||||
|
||||
return redirect(route('transactions.show', [$group->id]));
|
||||
}
|
||||
|
||||
@@ -191,15 +191,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'),
|
||||
@@ -217,7 +217,8 @@ class MassController extends Controller
|
||||
$service->setData($data);
|
||||
$service->update();
|
||||
// trigger rules
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true));
|
||||
$runRecalculations = $service->isCompareHashChanged();
|
||||
event(new UpdatedTransactionGroup($journal->transactionGroup, true, true, $runRecalculations));
|
||||
}
|
||||
|
||||
private function getDateFromRequest(MassEditJournalRequest $request, int $journalId, string $key): ?Carbon
|
||||
|
||||
@@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -41,15 +40,9 @@ class SelectTransactionsRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
// fixed
|
||||
/** @var Carbon $sessionFirst */
|
||||
$sessionFirst = clone session('first');
|
||||
$first = $sessionFirst->subDay()->format('Y-m-d');
|
||||
$today = today(config('app.timezone'))->addDay()->format('Y-m-d');
|
||||
|
||||
return [
|
||||
'start' => 'required|date|after:'.$first,
|
||||
'end' => 'required|date|before:'.$today,
|
||||
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before:end|required_with:end',
|
||||
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after:start|required_with:start',
|
||||
'accounts' => 'required',
|
||||
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
|
||||
@@ -67,9 +67,10 @@ class UserFailedLoginAttempt extends Notification
|
||||
{
|
||||
$settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
|
||||
$message = new Message();
|
||||
$ip = Request::ip();
|
||||
$message->topic($settings['ntfy_topic']);
|
||||
$message->title((string) trans('email.failed_login_subject'));
|
||||
$message->body((string) trans('email.failed_login_message', ['email' => $this->user->email]));
|
||||
$message->body((string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]));
|
||||
|
||||
return $message;
|
||||
}
|
||||
@@ -79,7 +80,9 @@ class UserFailedLoginAttempt extends Notification
|
||||
*/
|
||||
public function toPushover(User $notifiable): PushoverMessage
|
||||
{
|
||||
return PushoverMessage::create((string) trans('email.failed_login_message', ['email' => $this->user->email]))
|
||||
$ip = Request::ip();
|
||||
|
||||
return PushoverMessage::create((string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]))
|
||||
->title((string) trans('email.failed_login_subject'))
|
||||
;
|
||||
}
|
||||
@@ -89,7 +92,8 @@ class UserFailedLoginAttempt extends Notification
|
||||
*/
|
||||
public function toSlack(User $notifiable): SlackMessage
|
||||
{
|
||||
$message = (string) trans('email.failed_login_message', ['email' => $this->user->email]);
|
||||
$ip = Request::ip();
|
||||
$message = (string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]);
|
||||
|
||||
return new SlackMessage()->content($message);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ use FireflyIII\Events\Model\BudgetLimit\Created;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Deleted;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Updated;
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedName;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
|
||||
use FireflyIII\Events\NewVersionAvailable;
|
||||
@@ -210,6 +211,9 @@ class EventServiceProvider extends ServiceProvider
|
||||
ChangedAmount::class => [
|
||||
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount',
|
||||
],
|
||||
ChangedName::class => [
|
||||
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changedPiggyBankName',
|
||||
],
|
||||
|
||||
// budget related events: CRUD budget limit
|
||||
Created::class => [
|
||||
|
||||
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedName;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\PiggyBankFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -66,7 +67,7 @@ trait ModifiesPiggyBanks
|
||||
{
|
||||
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
|
||||
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
|
||||
$pivot->current_amount = bcsub((string) $currentAmount, $amount);
|
||||
$pivot->current_amount = bcsub((string)$currentAmount, $amount);
|
||||
$pivot->native_current_amount = null;
|
||||
|
||||
// also update native_current_amount.
|
||||
@@ -89,7 +90,7 @@ trait ModifiesPiggyBanks
|
||||
{
|
||||
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
|
||||
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
|
||||
$pivot->current_amount = bcadd((string) $currentAmount, $amount);
|
||||
$pivot->current_amount = bcadd((string)$currentAmount, $amount);
|
||||
$pivot->native_current_amount = null;
|
||||
|
||||
// also update native_current_amount.
|
||||
@@ -121,13 +122,13 @@ trait ModifiesPiggyBanks
|
||||
|
||||
|
||||
if (0 !== bccomp($piggyBank->target_amount, '0')) {
|
||||
$leftToSave = bcsub($piggyBank->target_amount, (string) $savedSoFar);
|
||||
$maxAmount = 1 === bccomp((string) $leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount;
|
||||
$leftToSave = bcsub($piggyBank->target_amount, (string)$savedSoFar);
|
||||
$maxAmount = 1 === bccomp((string)$leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount;
|
||||
Log::debug(sprintf('Left to save: %s', $leftToSave));
|
||||
Log::debug(sprintf('Maximum amount: %s', $maxAmount));
|
||||
}
|
||||
|
||||
$compare = bccomp($amount, (string) $maxAmount);
|
||||
$compare = bccomp($amount, (string)$maxAmount);
|
||||
$result = $compare <= 0;
|
||||
|
||||
Log::debug(sprintf('Compare <= 0? %d, so canAddAmount is %s', $compare, var_export($result, true)));
|
||||
@@ -139,7 +140,7 @@ trait ModifiesPiggyBanks
|
||||
{
|
||||
$savedSoFar = $this->getCurrentAmount($piggyBank, $account);
|
||||
|
||||
return bccomp($amount, (string) $savedSoFar) <= 0;
|
||||
return bccomp($amount, (string)$savedSoFar) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,7 +171,7 @@ trait ModifiesPiggyBanks
|
||||
if (1 === bccomp($amount, $max) && 0 !== bccomp($piggyBank->target_amount, '0')) {
|
||||
$amount = $max;
|
||||
}
|
||||
$difference = bcsub($amount, (string) $repetition->current_amount);
|
||||
$difference = bcsub($amount, (string)$repetition->current_amount);
|
||||
$repetition->current_amount = $amount;
|
||||
$repetition->save();
|
||||
|
||||
@@ -211,12 +212,12 @@ trait ModifiesPiggyBanks
|
||||
{
|
||||
$piggyBank = $this->updateProperties($piggyBank, $data);
|
||||
if (array_key_exists('notes', $data)) {
|
||||
$this->updateNote($piggyBank, (string) $data['notes']);
|
||||
$this->updateNote($piggyBank, (string)$data['notes']);
|
||||
}
|
||||
|
||||
// update the order of the piggy bank:
|
||||
$oldOrder = $piggyBank->order;
|
||||
$newOrder = (int) ($data['order'] ?? $oldOrder);
|
||||
$newOrder = (int)($data['order'] ?? $oldOrder);
|
||||
if ($oldOrder !== $newOrder) {
|
||||
$this->setOrder($piggyBank, $newOrder);
|
||||
}
|
||||
@@ -233,9 +234,9 @@ trait ModifiesPiggyBanks
|
||||
// if the piggy bank is now smaller than the sum of the money saved,
|
||||
// remove money from all accounts until the piggy bank is the right amount.
|
||||
$currentAmount = $this->getCurrentAmount($piggyBank);
|
||||
if (1 === bccomp((string) $currentAmount, (string) $piggyBank->target_amount) && 0 !== bccomp((string) $piggyBank->target_amount, '0')) {
|
||||
if (1 === bccomp((string)$currentAmount, (string)$piggyBank->target_amount) && 0 !== bccomp((string)$piggyBank->target_amount, '0')) {
|
||||
Log::debug(sprintf('Current amount is %s, target amount is %s', $currentAmount, $piggyBank->target_amount));
|
||||
$difference = bcsub((string) $piggyBank->target_amount, (string) $currentAmount);
|
||||
$difference = bcsub((string)$piggyBank->target_amount, (string)$currentAmount);
|
||||
|
||||
// an amount will be removed, create "negative" event:
|
||||
// Log::debug(sprintf('ChangedAmount: is triggered with difference "%s"', $difference));
|
||||
@@ -248,7 +249,7 @@ trait ModifiesPiggyBanks
|
||||
|
||||
// update using name:
|
||||
if (array_key_exists('object_group_title', $data)) {
|
||||
$objectGroupTitle = (string) $data['object_group_title'];
|
||||
$objectGroupTitle = (string)$data['object_group_title'];
|
||||
if ('' !== $objectGroupTitle) {
|
||||
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
|
||||
if (null !== $objectGroup) {
|
||||
@@ -264,7 +265,7 @@ trait ModifiesPiggyBanks
|
||||
|
||||
// try also with ID:
|
||||
if (array_key_exists('object_group_id', $data)) {
|
||||
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
|
||||
$objectGroupId = (int)($data['object_group_id'] ?? 0);
|
||||
if (0 !== $objectGroupId) {
|
||||
$objectGroup = $this->findObjectGroupById($objectGroupId);
|
||||
if (null !== $objectGroup) {
|
||||
@@ -282,6 +283,7 @@ trait ModifiesPiggyBanks
|
||||
private function updateProperties(PiggyBank $piggyBank, array $data): PiggyBank
|
||||
{
|
||||
if (array_key_exists('name', $data) && '' !== $data['name']) {
|
||||
event(new ChangedName($piggyBank, $piggyBank->name, $data['name']));
|
||||
$piggyBank->name = $data['name'];
|
||||
}
|
||||
if (array_key_exists('transaction_currency_id', $data) && is_int($data['transaction_currency_id'])) {
|
||||
@@ -366,14 +368,14 @@ trait ModifiesPiggyBanks
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
$current = $account->pivot->current_amount;
|
||||
// if this account contains more than the amount, remove the amount and return.
|
||||
if (1 === bccomp((string) $current, $amount)) {
|
||||
if (1 === bccomp((string)$current, $amount)) {
|
||||
$this->removeAmount($piggyBank, $account, $amount);
|
||||
|
||||
return;
|
||||
}
|
||||
// if this account contains less than the amount, remove the current amount, update the amount and continue.
|
||||
$this->removeAmount($piggyBank, $account, $current);
|
||||
$amount = bcsub($amount, (string) $current);
|
||||
$amount = bcsub($amount, (string)$current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
|
||||
use FireflyIII\User;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
@@ -438,4 +439,14 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
|
||||
|
||||
return $search->take($limit)->get(['piggy_banks.*']);
|
||||
}
|
||||
|
||||
public function resetHistory(PiggyBank $piggyBank): void
|
||||
{
|
||||
$piggyBank->piggyBankEvents()->delete();
|
||||
foreach ($piggyBank->accounts as $account) {
|
||||
if (0 !== bccomp('0', $account->pivot->current_amount)) {
|
||||
event(new ChangedAmount($piggyBank, $account->pivot->current_amount, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface PiggyBankRepositoryInterface
|
||||
{
|
||||
public function resetHistory(PiggyBank $piggyBank): void;
|
||||
|
||||
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
|
||||
|
||||
public function addAmountToPiggyBank(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): void;
|
||||
|
||||
@@ -217,7 +217,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
|
||||
'link' => $entry->outward,
|
||||
'group' => $entry->destination->transaction_group_id,
|
||||
'description' => $entry->destination->description,
|
||||
'editable' => 1 === (int) $entry->editable,
|
||||
'editable' => 1 === (int)$entry->editable,
|
||||
'amount' => $amount,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
];
|
||||
@@ -230,7 +230,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
|
||||
'link' => $entry->inward,
|
||||
'group' => $entry->source->transaction_group_id,
|
||||
'description' => $entry->source->description,
|
||||
'editable' => 1 === (int) $entry->editable,
|
||||
'editable' => 1 === (int)$entry->editable,
|
||||
'amount' => $amount,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
];
|
||||
@@ -264,7 +264,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
|
||||
if (null === $transaction->foreign_amount || '' === $transaction->foreign_amount) {
|
||||
return '';
|
||||
}
|
||||
if (0 === bccomp('0', (string) $transaction->foreign_amount)) {
|
||||
if (0 === bccomp('0', (string)$transaction->foreign_amount)) {
|
||||
return '';
|
||||
}
|
||||
$currency = $transaction->foreignCurrency;
|
||||
@@ -305,7 +305,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
|
||||
$return = [];
|
||||
|
||||
foreach ($query as $row) {
|
||||
$return[$row->name] = new Carbon(json_decode((string) $row->data, true, 512, JSON_THROW_ON_ERROR));
|
||||
$return[$row->name] = new Carbon(json_decode((string)$row->data, true, 512, JSON_THROW_ON_ERROR));
|
||||
}
|
||||
|
||||
return new NullArrayObject($return);
|
||||
@@ -325,7 +325,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
|
||||
$return = [];
|
||||
|
||||
foreach ($query as $row) {
|
||||
$return[$row->name] = json_decode((string) $row->data);
|
||||
$return[$row->name] = json_decode((string)$row->data);
|
||||
}
|
||||
|
||||
return new NullArrayObject($return);
|
||||
@@ -432,4 +432,23 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
|
||||
|
||||
return $service->update($transactionGroup, $data);
|
||||
}
|
||||
|
||||
public function getCompareHash(TransactionGroup $group): string
|
||||
{
|
||||
$sum = '0';
|
||||
$names = '';
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($group->transactionJournals as $journal) {
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions as $transaction) {
|
||||
if (-1 === bccomp('0', (string)$transaction->amount)) {
|
||||
$sum = bcadd($sum, $transaction->amount);
|
||||
$names = sprintf('%s%s', $names, $transaction->account->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hash('sha256', sprintf('%s-%s', $names, $sum));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ interface TransactionGroupRepositoryInterface
|
||||
{
|
||||
public function countAttachments(int $journalId): int;
|
||||
|
||||
/**
|
||||
* Small method that returns a hash that can be used to compare two transaction groups.
|
||||
*/
|
||||
public function getCompareHash(TransactionGroup $group): string;
|
||||
|
||||
public function destroy(TransactionGroup $group): void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,6 +43,7 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
@@ -58,36 +59,39 @@ class JournalUpdateService
|
||||
{
|
||||
use JournalServiceTrait;
|
||||
|
||||
private BillRepositoryInterface $billRepository;
|
||||
private BillRepositoryInterface $billRepository;
|
||||
private CurrencyRepositoryInterface $currencyRepository;
|
||||
private array $data;
|
||||
private ?Account $destinationAccount;
|
||||
private ?Transaction $destinationTransaction;
|
||||
private array $metaDate;
|
||||
private array $metaString;
|
||||
private ?Account $sourceAccount;
|
||||
private ?Transaction $sourceTransaction;
|
||||
private ?TransactionGroup $transactionGroup;
|
||||
private ?TransactionJournal $transactionJournal;
|
||||
private TransactionGroupRepositoryInterface $transactionGroupRepository;
|
||||
private array $data;
|
||||
private ?Account $destinationAccount;
|
||||
private ?Transaction $destinationTransaction;
|
||||
private array $metaDate;
|
||||
private array $metaString;
|
||||
private ?Account $sourceAccount;
|
||||
private ?Transaction $sourceTransaction;
|
||||
private ?TransactionGroup $transactionGroup;
|
||||
private ?TransactionJournal $transactionJournal;
|
||||
private string $startCompareHash = '';
|
||||
|
||||
/**
|
||||
* JournalUpdateService constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->destinationAccount = null;
|
||||
$this->destinationTransaction = null;
|
||||
$this->sourceAccount = null;
|
||||
$this->sourceTransaction = null;
|
||||
$this->transactionGroup = null;
|
||||
$this->transactionJournal = null;
|
||||
$this->billRepository = app(BillRepositoryInterface::class);
|
||||
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||
$this->budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$this->tagFactory = app(TagFactory::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||
$this->metaString = [
|
||||
$this->destinationAccount = null;
|
||||
$this->destinationTransaction = null;
|
||||
$this->sourceAccount = null;
|
||||
$this->sourceTransaction = null;
|
||||
$this->transactionGroup = null;
|
||||
$this->transactionJournal = null;
|
||||
$this->billRepository = app(BillRepositoryInterface::class);
|
||||
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||
$this->budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$this->tagFactory = app(TagFactory::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||
$this->transactionGroupRepository = app(TransactionGroupRepositoryInterface::class);
|
||||
$this->metaString = [
|
||||
'sepa_cc',
|
||||
'sepa_ct_op',
|
||||
'sepa_ct_id',
|
||||
@@ -102,7 +106,7 @@ class JournalUpdateService
|
||||
'external_id',
|
||||
'external_url',
|
||||
];
|
||||
$this->metaDate = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date',
|
||||
$this->metaDate = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date',
|
||||
'invoice_date', ];
|
||||
}
|
||||
|
||||
@@ -119,10 +123,12 @@ class JournalUpdateService
|
||||
$this->budgetRepository->setUser($transactionGroup->user);
|
||||
$this->tagFactory->setUser($transactionGroup->user);
|
||||
$this->accountRepository->setUser($transactionGroup->user);
|
||||
$this->transactionGroupRepository->setUser($transactionGroup->user);
|
||||
$this->destinationAccount = null;
|
||||
$this->destinationTransaction = null;
|
||||
$this->sourceAccount = null;
|
||||
$this->sourceTransaction = null;
|
||||
$this->startCompareHash = $this->transactionGroupRepository->getCompareHash($transactionGroup);
|
||||
}
|
||||
|
||||
public function setTransactionJournal(TransactionJournal $transactionJournal): void
|
||||
@@ -338,7 +344,7 @@ class JournalUpdateService
|
||||
}
|
||||
|
||||
$sourceInfo = [
|
||||
'id' => (int) ($this->data['source_id'] ?? null),
|
||||
'id' => (int)($this->data['source_id'] ?? null),
|
||||
'name' => $this->data['source_name'] ?? null,
|
||||
'iban' => $this->data['source_iban'] ?? null,
|
||||
'number' => $this->data['source_number'] ?? null,
|
||||
@@ -402,7 +408,7 @@ class JournalUpdateService
|
||||
}
|
||||
|
||||
$destInfo = [
|
||||
'id' => (int) ($this->data['destination_id'] ?? null),
|
||||
'id' => (int)($this->data['destination_id'] ?? null),
|
||||
'name' => $this->data['destination_name'] ?? null,
|
||||
'iban' => $this->data['destination_iban'] ?? null,
|
||||
'number' => $this->data['destination_number'] ?? null,
|
||||
@@ -468,8 +474,8 @@ class JournalUpdateService
|
||||
)
|
||||
&& TransactionTypeEnum::WITHDRAWAL->value === $type
|
||||
) {
|
||||
$billId = (int) ($this->data['bill_id'] ?? 0);
|
||||
$billName = (string) ($this->data['bill_name'] ?? '');
|
||||
$billId = (int)($this->data['bill_id'] ?? 0);
|
||||
$billName = (string)($this->data['bill_name'] ?? '');
|
||||
$bill = $this->billRepository->findBill($billId, $billName);
|
||||
$this->transactionJournal->bill_id = $bill?->id;
|
||||
Log::debug('Updated bill ID');
|
||||
@@ -481,7 +487,7 @@ class JournalUpdateService
|
||||
*/
|
||||
private function updateField(string $fieldName): void
|
||||
{
|
||||
if (array_key_exists($fieldName, $this->data) && '' !== (string) $this->data[$fieldName]) {
|
||||
if (array_key_exists($fieldName, $this->data) && '' !== (string)$this->data[$fieldName]) {
|
||||
$value = $this->data[$fieldName];
|
||||
|
||||
if ('date' === $fieldName) {
|
||||
@@ -557,7 +563,7 @@ class JournalUpdateService
|
||||
{
|
||||
// update notes.
|
||||
if ($this->hasFields(['notes'])) {
|
||||
$notes = '' === (string) $this->data['notes'] ? null : $this->data['notes'];
|
||||
$notes = '' === (string)$this->data['notes'] ? null : $this->data['notes'];
|
||||
$this->storeNotes($this->transactionJournal, $notes);
|
||||
}
|
||||
}
|
||||
@@ -605,7 +611,7 @@ class JournalUpdateService
|
||||
foreach ($this->metaDate as $field) {
|
||||
if ($this->hasFields([$field])) {
|
||||
try {
|
||||
$value = '' === (string) $this->data[$field] ? null : new Carbon($this->data[$field]);
|
||||
$value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]);
|
||||
} catch (InvalidDateException|InvalidFormatException $e) { // @phpstan-ignore-line
|
||||
Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage()));
|
||||
|
||||
@@ -673,7 +679,6 @@ class JournalUpdateService
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$origSourceTransaction = $this->getSourceTransaction();
|
||||
$origSourceTransaction->amount = app('steam')->negative($amount);
|
||||
$origSourceTransaction->balance_dirty = true;
|
||||
@@ -705,7 +710,7 @@ class JournalUpdateService
|
||||
$newForeignId = $this->data['foreign_currency_id'] ?? null;
|
||||
$newForeignCode = $this->data['foreign_currency_code'] ?? null;
|
||||
$foreignCurrency = $this->currencyRepository->findCurrencyNull($newForeignId, $newForeignCode)
|
||||
?? $foreignCurrency;
|
||||
?? $foreignCurrency;
|
||||
|
||||
// not the same as normal currency
|
||||
if (null !== $foreignCurrency && $foreignCurrency->id === $this->transactionJournal->transaction_currency_id) {
|
||||
@@ -816,4 +821,14 @@ class JournalUpdateService
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isCompareHashChanged(): bool
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$compareHash = $this->transactionGroupRepository->getCompareHash($this->transactionGroup);
|
||||
Log::debug(sprintf('Compare hash is "%s".', $compareHash));
|
||||
Log::debug(sprintf('Start compare hash is "%s".', $this->startCompareHash));
|
||||
|
||||
return $compareHash !== $this->startCompareHash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Jobs\CreateRecurringTransactions;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class RecurringCronjob
|
||||
@@ -39,34 +41,34 @@ class RecurringCronjob extends AbstractCronjob
|
||||
*/
|
||||
public function fire(): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
/** @var Configuration $config */
|
||||
$config = app('fireflyconfig')->get('last_rt_job', 0);
|
||||
$config = FireflyConfig::get('last_rt_job', 0);
|
||||
$lastTime = (int) $config->data;
|
||||
$diff = Carbon::now()->getTimestamp() - $lastTime;
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
|
||||
if (0 === $lastTime) {
|
||||
app('log')->info('Recurring transactions cron-job has never fired before.');
|
||||
Log::info('Recurring transactions cron-job has never fired before.');
|
||||
}
|
||||
// less than half a day ago:
|
||||
if ($lastTime > 0 && $diff <= 43200) {
|
||||
app('log')->info(sprintf('It has been %s since the recurring transactions cron-job has fired.', $diffForHumans));
|
||||
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired.', $diffForHumans));
|
||||
if (false === $this->force) {
|
||||
app('log')->info('The cron-job will not fire now.');
|
||||
$this->message = sprintf('It has been %s since the recurring transactions cron-job has fired. It will not fire now.', $diffForHumans);
|
||||
Log::info('The cron-job will not fire now.');
|
||||
$this->message = sprintf('It has been "%s" since the recurring transactions cron-job has fired. It will not fire now.', $diffForHumans);
|
||||
$this->jobFired = false;
|
||||
$this->jobErrored = false;
|
||||
$this->jobSucceeded = false;
|
||||
|
||||
return;
|
||||
}
|
||||
app('log')->info('Execution of the recurring transaction cron-job has been FORCED.');
|
||||
Log::info('Execution of the recurring transaction cron-job has been FORCED.');
|
||||
}
|
||||
|
||||
if ($lastTime > 0 && $diff > 43200) {
|
||||
app('log')->info(sprintf('It has been %s since the recurring transactions cron-job has fired. It will fire now!', $diffForHumans));
|
||||
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired. It will fire now!', $diffForHumans));
|
||||
}
|
||||
|
||||
$this->fireRecurring();
|
||||
@@ -76,7 +78,7 @@ class RecurringCronjob extends AbstractCronjob
|
||||
|
||||
private function fireRecurring(): void
|
||||
{
|
||||
app('log')->info(sprintf('Will now fire recurring cron job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
|
||||
Log::info(sprintf('Will now fire recurring cron job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
|
||||
|
||||
$job = new CreateRecurringTransactions($this->date);
|
||||
$job->setForce($this->force);
|
||||
@@ -88,8 +90,8 @@ class RecurringCronjob extends AbstractCronjob
|
||||
$this->jobSucceeded = true;
|
||||
$this->message = 'Recurring transactions cron job fired successfully.';
|
||||
|
||||
app('fireflyconfig')->set('last_rt_job', (int) $this->date->format('U'));
|
||||
app('log')->info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
|
||||
app('log')->info('Done with recurring cron job task.');
|
||||
FireflyConfig::set('last_rt_job', (int) $this->date->format('U'));
|
||||
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
|
||||
Log::info('Done with recurring cron job task.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class FireflyConfig
|
||||
{
|
||||
public function delete(string $name): void
|
||||
{
|
||||
$fullName = 'ff-config-'.$name;
|
||||
$fullName = 'ff3-config-'.$name;
|
||||
if (Cache::has($fullName)) {
|
||||
Cache::forget($fullName);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class FireflyConfig
|
||||
*/
|
||||
public function get(string $name, mixed $default = null): ?Configuration
|
||||
{
|
||||
$fullName = 'ff-config-'.$name;
|
||||
$fullName = 'ff3-config-'.$name;
|
||||
if (Cache::has($fullName)) {
|
||||
return Cache::get($fullName);
|
||||
}
|
||||
|
||||
@@ -79,12 +79,12 @@ class ExchangeRateConverter
|
||||
public function getCurrencyRate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string
|
||||
{
|
||||
if (false === $this->enabled()) {
|
||||
Log::debug('ExchangeRateConverter: disabled, return "1".');
|
||||
// Log::debug('ExchangeRateConverter: disabled, return "1".');
|
||||
|
||||
return '1';
|
||||
}
|
||||
if ($from->id === $to->id) {
|
||||
Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
|
||||
// Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -205,7 +206,7 @@ trait GetConfigurationData
|
||||
|
||||
protected function verifyRecurringCronJob(): void
|
||||
{
|
||||
$config = app('fireflyconfig')->get('last_rt_job', 0);
|
||||
$config = FireflyConfig::get('last_rt_job', 0);
|
||||
$lastTime = (int) $config?->data;
|
||||
$now = Carbon::now()->getTimestamp();
|
||||
app('log')->debug(sprintf('verifyRecurringCronJob: last time is %d ("%s"), now is %d', $lastTime, $config?->data, $now));
|
||||
|
||||
@@ -35,6 +35,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Debug\Timer;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Trait PeriodOverview.
|
||||
@@ -77,6 +78,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array
|
||||
{
|
||||
Log::debug('Now in getAccountPeriodOverview()');
|
||||
Timer::start('account-period-total');
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
@@ -100,6 +102,7 @@ trait PeriodOverview
|
||||
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
|
||||
|
||||
// loop dates
|
||||
Log::debug(sprintf('Count of loops: %d', count($dates)));
|
||||
foreach ($dates as $currentDate) {
|
||||
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
|
||||
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
|
||||
@@ -119,6 +122,7 @@ trait PeriodOverview
|
||||
}
|
||||
$cache->store($entries);
|
||||
Timer::stop('account-period-total');
|
||||
Log::debug('End of getAccountPeriodOverview()');
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
@@ -30,10 +30,12 @@ use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Location;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -52,6 +54,7 @@ class TransactionGroupEnrichment implements EnrichmentInterface
|
||||
private array $notes; // @phpstan-ignore-line
|
||||
private array $tags;
|
||||
private User $user;
|
||||
private TransactionCurrency $nativeCurrency;
|
||||
private UserGroup $userGroup;
|
||||
|
||||
public function __construct()
|
||||
@@ -63,6 +66,7 @@ class TransactionGroupEnrichment implements EnrichmentInterface
|
||||
$this->locations = [];
|
||||
$this->attachmentCount = [];
|
||||
$this->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
|
||||
$this->nativeCurrency = Amount::getNativeCurrency();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
@@ -192,8 +196,9 @@ class TransactionGroupEnrichment implements EnrichmentInterface
|
||||
$metaData = $this->metaData;
|
||||
$locations = $this->locations;
|
||||
$attachmentCount = $this->attachmentCount;
|
||||
$nativeCurrency = $this->nativeCurrency;
|
||||
|
||||
$this->collection = $this->collection->map(function (array $item) use ($notes, $tags, $metaData, $locations, $attachmentCount) {
|
||||
$this->collection = $this->collection->map(function (array $item) use ($nativeCurrency, $notes, $tags, $metaData, $locations, $attachmentCount) {
|
||||
foreach ($item['transactions'] as $index => $transaction) {
|
||||
$journalId = (int) $transaction['transaction_journal_id'];
|
||||
|
||||
@@ -213,6 +218,15 @@ class TransactionGroupEnrichment implements EnrichmentInterface
|
||||
'zoom_level' => null,
|
||||
];
|
||||
|
||||
// native currency
|
||||
$item['transactions'][$index]['native_currency'] = [
|
||||
'id' => (string) $nativeCurrency->id,
|
||||
'code' => $nativeCurrency->code,
|
||||
'name' => $nativeCurrency->name,
|
||||
'symbol' => $nativeCurrency->symbol,
|
||||
'decimal_places' => $nativeCurrency->decimal_places,
|
||||
];
|
||||
|
||||
// append meta data
|
||||
$item['transactions'][$index]['meta'] = [];
|
||||
$item['transactions'][$index]['meta_date'] = [];
|
||||
|
||||
@@ -67,6 +67,16 @@ class UpdatePiggyBank implements ActionInterface
|
||||
|
||||
Log::debug(sprintf('Found piggy bank #%d ("%s")', $piggyBank->id, $piggyBank->name));
|
||||
|
||||
// piggy bank already has an event for this transaction journal?
|
||||
if ($this->alreadyEventPresent($piggyBank, $journal)) {
|
||||
Log::info(sprintf('Piggy bank #%d ("%s") already has an event for transaction journal #%d, so no action will be taken.', $piggyBank->id, $piggyBank->name, $journalObj->id));
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_piggy', ['name' => $actionValue])));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** @var Transaction $destination */
|
||||
$destination = $journalObj->transactions()->where('amount', '>', 0)->first();
|
||||
|
||||
@@ -231,4 +241,9 @@ class UpdatePiggyBank implements ActionInterface
|
||||
|
||||
$repository->addAmount($piggyBank, $account, $amount, $journal);
|
||||
}
|
||||
|
||||
private function alreadyEventPresent(PiggyBank $piggyBank, array $journal): bool
|
||||
{
|
||||
return $piggyBank->piggyBankEvents()->where('transaction_journal_id', $journal['transaction_journal_id'])->exists();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,12 +144,38 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
|
||||
'foreign_currency_id' => $this->stringFromArray($transaction, 'foreign_currency_id', null),
|
||||
'foreign_currency_code' => $transaction['foreign_currency_code'],
|
||||
'foreign_currency_name' => $transaction['foreign_currency_name'],
|
||||
'foreign_currency_symbol' => $transaction['foreign_currency_symbol'],
|
||||
'foreign_currency_decimal_places' => $transaction['foreign_currency_decimal_places'],
|
||||
|
||||
'amount' => $amount,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
|
||||
// native amount, defaults to NULL when convertToNative is false.
|
||||
'native_amount' => $transaction['native_amount'] ?? null,
|
||||
|
||||
// native currency, always present.
|
||||
'native_currency_id' => $transaction['native_currency']['id'] ?? null,
|
||||
'native_currency_code' => $transaction['native_currency']['code'] ?? null,
|
||||
'native_currency_name' => $transaction['native_currency']['name'] ?? null,
|
||||
'native_currency_symbol' => $transaction['native_currency']['symbol'] ?? null,
|
||||
'native_currency_decimal_places' => $transaction['native_currency']['decimal_places'] ?? null,
|
||||
|
||||
// source balance after
|
||||
'source_balance_after' => $transaction['source_balance_after'] ?? null,
|
||||
'source_balance_dirty' => $transaction['source_balance_dirty'],
|
||||
|
||||
// destination balance after
|
||||
'destination_balance_after' => $transaction['destination_balance_after'] ?? null,
|
||||
'destination_balance_dirty' => $transaction['destination_balance_dirty'],
|
||||
|
||||
// balance before and after, if not dirty.
|
||||
// 'running_balance_dirty' => $transaction['balance_dirty'] ?? false,
|
||||
// 'running_balance_before' => $transaction['balance_before'] ?? null,
|
||||
// 'running_balance_after' => $transaction['balance_after'] ?? null,
|
||||
|
||||
|
||||
|
||||
'description' => $transaction['description'],
|
||||
|
||||
'source_id' => (string) $transaction['source_account_id'],
|
||||
|
||||
160
composer.lock
generated
160
composer.lock
generated
@@ -129,16 +129,16 @@
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.12.3",
|
||||
"version": "0.13.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
|
||||
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04",
|
||||
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -177,7 +177,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.12.3"
|
||||
"source": "https://github.com/brick/math/tree/0.13.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -185,7 +185,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-28T13:11:00+00:00"
|
||||
"time": "2025-03-29T13:50:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
@@ -939,16 +939,16 @@
|
||||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.18.0",
|
||||
"version": "2.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
|
||||
"reference": "8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
|
||||
"reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26",
|
||||
"reference": "8fcc6a862f2e7b94eb4221fd0819ddba3d30ab26",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -998,7 +998,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/filp/whoops/issues",
|
||||
"source": "https://github.com/filp/whoops/tree/2.18.0"
|
||||
"source": "https://github.com/filp/whoops/tree/2.18.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1006,7 +1006,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-15T12:00:00+00:00"
|
||||
"time": "2025-06-03T18:56:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "firebase/php-jwt",
|
||||
@@ -1879,20 +1879,20 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v12.16.0",
|
||||
"version": "v12.17.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "293bb1c70224faebfd3d4328e201c37115da055f"
|
||||
"reference": "8729d084510480fdeec9b6ad198180147d4a7f06"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/293bb1c70224faebfd3d4328e201c37115da055f",
|
||||
"reference": "293bb1c70224faebfd3d4328e201c37115da055f",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8729d084510480fdeec9b6ad198180147d4a7f06",
|
||||
"reference": "8729d084510480fdeec9b6ad198180147d4a7f06",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.11|^0.12",
|
||||
"brick/math": "^0.11|^0.12|^0.13",
|
||||
"composer-runtime-api": "^2.2",
|
||||
"doctrine/inflector": "^2.0.5",
|
||||
"dragonmantank/cron-expression": "^3.4",
|
||||
@@ -2090,7 +2090,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2025-05-27T15:49:44+00:00"
|
||||
"time": "2025-06-03T14:04:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
@@ -3473,22 +3473,22 @@
|
||||
},
|
||||
{
|
||||
"name": "mailersend/laravel-driver",
|
||||
"version": "v2.9.1",
|
||||
"version": "v2.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mailersend/mailersend-laravel-driver.git",
|
||||
"reference": "87fd5ab76808bbaac9221be0d306baef13e98725"
|
||||
"reference": "63acebb5064745076df27b1a80423986b6d7b69e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/87fd5ab76808bbaac9221be0d306baef13e98725",
|
||||
"reference": "87fd5ab76808bbaac9221be0d306baef13e98725",
|
||||
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/63acebb5064745076df27b1a80423986b6d7b69e",
|
||||
"reference": "63acebb5064745076df27b1a80423986b6d7b69e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
|
||||
"mailersend/mailersend": "^0.31.0",
|
||||
"mailersend/mailersend": "^0.34.0",
|
||||
"nyholm/psr7": "^1.5",
|
||||
"php": ">=8.0",
|
||||
"php-http/guzzle7-adapter": "^1.0",
|
||||
@@ -3536,29 +3536,28 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mailersend/mailersend-laravel-driver/issues",
|
||||
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.9.1"
|
||||
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.11.0"
|
||||
},
|
||||
"time": "2025-04-09T09:33:07+00:00"
|
||||
"time": "2025-06-04T08:47:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mailersend/mailersend",
|
||||
"version": "v0.31.0",
|
||||
"version": "v0.34.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mailersend/mailersend-php.git",
|
||||
"reference": "513ff83ee768526055ad52987cde401ea7218c67"
|
||||
"reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/513ff83ee768526055ad52987cde401ea7218c67",
|
||||
"reference": "513ff83ee768526055ad52987cde401ea7218c67",
|
||||
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
|
||||
"reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"beberlei/assert": "^3.2",
|
||||
"ext-json": "*",
|
||||
"illuminate/collections": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
|
||||
"php": "^7.4|^8.0",
|
||||
"php": "^7.4 || ^8.0 <8.5",
|
||||
"php-http/client-common": "^2.2",
|
||||
"php-http/discovery": "^1.9",
|
||||
"php-http/httplug": "^2.1",
|
||||
@@ -3603,9 +3602,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mailersend/mailersend-php/issues",
|
||||
"source": "https://github.com/mailersend/mailersend-php/tree/v0.31.0"
|
||||
"source": "https://github.com/mailersend/mailersend-php/tree/v0.34.0"
|
||||
},
|
||||
"time": "2025-04-03T12:16:11+00:00"
|
||||
"time": "2025-06-04T07:53:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
@@ -3880,16 +3879,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.0.6",
|
||||
"version": "v4.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "ce708655043c7050eb050df361c5e313cf708309"
|
||||
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/ce708655043c7050eb050df361c5e313cf708309",
|
||||
"reference": "ce708655043c7050eb050df361c5e313cf708309",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2",
|
||||
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3960,9 +3959,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.6"
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.7"
|
||||
},
|
||||
"time": "2025-03-30T21:06:30+00:00"
|
||||
"time": "2025-06-03T04:55:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
@@ -5747,20 +5746,20 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.7.6",
|
||||
"version": "4.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "91039bc1faa45ba123c4328958e620d382ec7088"
|
||||
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
|
||||
"reference": "91039bc1faa45ba123c4328958e620d382ec7088",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
|
||||
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
|
||||
"ext-json": "*",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
@@ -5769,26 +5768,23 @@
|
||||
"rhumsaa/uuid": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/captainhook": "^5.10",
|
||||
"captainhook/captainhook": "^5.25",
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"doctrine/annotations": "^1.8",
|
||||
"ergebnis/composer-normalize": "^2.15",
|
||||
"mockery/mockery": "^1.3",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"ergebnis/composer-normalize": "^2.47",
|
||||
"mockery/mockery": "^1.6",
|
||||
"paragonie/random-lib": "^2",
|
||||
"php-mock/php-mock": "^2.2",
|
||||
"php-mock/php-mock-mockery": "^1.3",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.1",
|
||||
"phpbench/phpbench": "^1.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpunit/phpunit": "^8.5 || ^9",
|
||||
"ramsey/composer-repl": "^1.4",
|
||||
"slevomat/coding-standard": "^8.4",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"vimeo/psalm": "^4.9"
|
||||
"php-mock/php-mock": "^2.6",
|
||||
"php-mock/php-mock-mockery": "^1.5",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4.0",
|
||||
"phpbench/phpbench": "^1.2.14",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-mockery": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"slevomat/coding-standard": "^8.18",
|
||||
"squizlabs/php_codesniffer": "^3.13"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
|
||||
@@ -5823,19 +5819,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.7.6"
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.8.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ramsey",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-27T21:32:50+00:00"
|
||||
"time": "2025-06-01T06:28:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rcrowe/twigbridge",
|
||||
@@ -10784,16 +10770,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.4.0",
|
||||
"version": "v5.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
|
||||
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
|
||||
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
|
||||
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10836,9 +10822,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
|
||||
},
|
||||
"time": "2024-12-30T11:07:19+00:00"
|
||||
"time": "2025-05-31T08:24:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@@ -11670,21 +11656,21 @@
|
||||
},
|
||||
{
|
||||
"name": "rector/rector",
|
||||
"version": "2.0.16",
|
||||
"version": "2.0.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rectorphp/rector.git",
|
||||
"reference": "f1366d1f8c7490541c8f7af6e5c7cef7cca1b5a2"
|
||||
"reference": "caa4ffda1d48bde44434e6ba95d132ec32e7fd40"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rectorphp/rector/zipball/f1366d1f8c7490541c8f7af6e5c7cef7cca1b5a2",
|
||||
"reference": "f1366d1f8c7490541c8f7af6e5c7cef7cca1b5a2",
|
||||
"url": "https://api.github.com/repos/rectorphp/rector/zipball/caa4ffda1d48bde44434e6ba95d132ec32e7fd40",
|
||||
"reference": "caa4ffda1d48bde44434e6ba95d132ec32e7fd40",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4|^8.0",
|
||||
"phpstan/phpstan": "^2.1.14"
|
||||
"phpstan/phpstan": "^2.1.17"
|
||||
},
|
||||
"conflict": {
|
||||
"rector/rector-doctrine": "*",
|
||||
@@ -11717,7 +11703,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/rectorphp/rector/issues",
|
||||
"source": "https://github.com/rectorphp/rector/tree/2.0.16"
|
||||
"source": "https://github.com/rectorphp/rector/tree/2.0.17"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -11725,7 +11711,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-12T16:37:16+00:00"
|
||||
"time": "2025-05-30T10:59:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
||||
@@ -78,7 +78,7 @@ return [
|
||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2025-05-29',
|
||||
'version' => 'develop/2025-06-04',
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 25,
|
||||
|
||||
|
||||
112
package-lock.json
generated
112
package-lock.json
generated
@@ -43,9 +43,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz",
|
||||
"integrity": "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==",
|
||||
"version": "7.27.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz",
|
||||
"integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -53,9 +53,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.3.tgz",
|
||||
"integrity": "sha512-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA==",
|
||||
"version": "7.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz",
|
||||
"integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -64,10 +64,10 @@
|
||||
"@babel/generator": "^7.27.3",
|
||||
"@babel/helper-compilation-targets": "^7.27.2",
|
||||
"@babel/helper-module-transforms": "^7.27.3",
|
||||
"@babel/helpers": "^7.27.3",
|
||||
"@babel/parser": "^7.27.3",
|
||||
"@babel/helpers": "^7.27.4",
|
||||
"@babel/parser": "^7.27.4",
|
||||
"@babel/template": "^7.27.2",
|
||||
"@babel/traverse": "^7.27.3",
|
||||
"@babel/traverse": "^7.27.4",
|
||||
"@babel/types": "^7.27.3",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
@@ -94,13 +94,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.3.tgz",
|
||||
"integrity": "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==",
|
||||
"version": "7.27.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz",
|
||||
"integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.27.3",
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@babel/types": "^7.27.3",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
@@ -392,9 +392,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.3.tgz",
|
||||
"integrity": "sha512-h/eKy9agOya1IGuLaZ9tEUgz+uIRXcbtOhRtUyyMf8JFmn1iT13vnl/IGVWSkdOCG/pC57U4S1jnAabAavTMwg==",
|
||||
"version": "7.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.4.tgz",
|
||||
"integrity": "sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -406,9 +406,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.3.tgz",
|
||||
"integrity": "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw==",
|
||||
"version": "7.27.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz",
|
||||
"integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -683,9 +683,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoping": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.3.tgz",
|
||||
"integrity": "sha512-+F8CnfhuLhwUACIJMLWnjz6zvzYM2r0yeIHKlbgfw7ml8rOMJsXNXV/hyRcb3nb493gRs4WvYpQAndWj/qQmkQ==",
|
||||
"version": "7.27.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz",
|
||||
"integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1255,9 +1255,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-regenerator": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz",
|
||||
"integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==",
|
||||
"version": "7.27.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.5.tgz",
|
||||
"integrity": "sha512-uhB8yHerfe3MWnuLAhEbeQ4afVoqv8BQsPqrTv7e/jZ9y00kJL6l9a/f4OWaKxotmjzewfEyXE1vgDJenkQ2/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1304,9 +1304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-runtime": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.3.tgz",
|
||||
"integrity": "sha512-bA9ZL5PW90YwNgGfjg6U+7Qh/k3zCEQJ06BFgAGRp/yMjw9hP9UGbGPtx3KSOkHGljEPCCxaE+PH4fUR2h1sDw==",
|
||||
"version": "7.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.4.tgz",
|
||||
"integrity": "sha512-D68nR5zxU64EUzV8i7T3R5XP0Xhrou/amNnddsRQssx6GrTLdZl1rLxyjtVZBd+v/NVX4AbTPOB5aU8thAZV1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1592,9 +1592,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz",
|
||||
"integrity": "sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==",
|
||||
"version": "7.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz",
|
||||
"integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1616,15 +1616,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.27.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.3.tgz",
|
||||
"integrity": "sha512-lId/IfN/Ye1CIu8xG7oKBHXd2iNb2aW1ilPszzGcJug6M8RCKfVNcYhpI5+bMvFYjK7lXIM0R+a+6r8xhHp2FQ==",
|
||||
"version": "7.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz",
|
||||
"integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.27.3",
|
||||
"@babel/parser": "^7.27.3",
|
||||
"@babel/parser": "^7.27.4",
|
||||
"@babel/template": "^7.27.2",
|
||||
"@babel/types": "^7.27.3",
|
||||
"debug": "^4.3.1",
|
||||
@@ -3108,9 +3108,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.15.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.24.tgz",
|
||||
"integrity": "sha512-w9CZGm9RDjzTh/D+hFwlBJ3ziUaVw7oufKA3vOFSOZlzmW9AkZnfjPb+DLnrV6qtgL/LNmP0/2zBNCFHL3F0ng==",
|
||||
"version": "22.15.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz",
|
||||
"integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4417,9 +4417,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001720",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
|
||||
"integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==",
|
||||
"version": "1.0.30001721",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
|
||||
"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -5632,9 +5632,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.161",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz",
|
||||
"integrity": "sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==",
|
||||
"version": "1.5.165",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
|
||||
"integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -7713,9 +7713,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/laravel-vite-plugin": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.2.0.tgz",
|
||||
"integrity": "sha512-R0pJ+IcTVeqEMoKz/B2Ij57QVq3sFTABiFmb06gAwFdivbOgsUtuhX6N2MGLEArajrS3U5JbberzwOe7uXHMHQ==",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.3.0.tgz",
|
||||
"integrity": "sha512-P5qyG56YbYxM8OuYmK2OkhcKe0AksNVJUjq9LUZ5tOekU9fBn9LujYyctI4t9XoLjuMvHJXXpCoPntY1oKltuA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10064,9 +10064,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.89.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.89.0.tgz",
|
||||
"integrity": "sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==",
|
||||
"version": "1.89.1",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.89.1.tgz",
|
||||
"integrity": "sha512-eMLLkl+qz7tx/0cJ9wI+w09GQ2zodTkcE/aVfywwdlRcI3EO19xGnbmJwg/JMIm+5MxVJ6outddLZ4Von4E++Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10414,9 +10414,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
|
||||
"integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -12081,9 +12081,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/webpack-sources": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.0.tgz",
|
||||
"integrity": "sha512-77R0RDmJfj9dyv5p3bM5pOHa+X8/ZkO9c7kpDstigkC4nIDobadsfSGCwB4bKhMVxqAok8tajaoR8rirM7+VFQ==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.2.tgz",
|
||||
"integrity": "sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -24,4 +24,12 @@ $(function () {
|
||||
if (typeof(lineChart) === 'function' && typeof(piggyBankID) !== 'undefined') {
|
||||
lineChart('chart/piggy-bank/' + piggyBankID, 'piggy-bank-history');
|
||||
}
|
||||
});
|
||||
|
||||
// on submit of logout button:
|
||||
$('.reset-link').click(function(e) {
|
||||
console.log('here we are');
|
||||
e.preventDefault();
|
||||
document.getElementById('reset-form').submit();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -183,6 +183,6 @@
|
||||
},
|
||||
"config": {
|
||||
"html_language": "zh-tw",
|
||||
"date_time_fns": "yyyy\u5e74 M\u6708 D\u65e5 dddd \u65bc HH:mm:ss"
|
||||
"date_time_fns": "yyyy\u5e74 M\u6708 d\u65e5 \u65bc HH:mm:ss"
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export default class Get {
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
list(params) {
|
||||
return api.get('/api/v2/budgets', {params: params});
|
||||
return api.get('/api/v1/budgets', {params: params});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -490,14 +490,15 @@ let transactions = function () {
|
||||
// addedSplit, is called from the HTML
|
||||
// for source account
|
||||
const renderAccount = function (item, b, c) {
|
||||
return item.title + '<br><small class="text-muted">' + i18next.t('firefly.account_type_' + item.meta.type) + '</small>';
|
||||
return item.name_with_balance + '<br><small class="text-muted">' + i18next.t('firefly.account_type_' + item.type) + '</small>';
|
||||
};
|
||||
console.log('here we are in');
|
||||
addAutocomplete({
|
||||
selector: 'input.ac-source',
|
||||
serverUrl: urls.account,
|
||||
onRenderItem: renderAccount,
|
||||
valueField: 'id',
|
||||
labelField: 'title',
|
||||
labelField: 'name_with_balance',
|
||||
onChange: changeSourceAccount,
|
||||
onSelectItem: selectSourceAccount,
|
||||
hiddenValue: this.entries[count].source_account.alpine_name
|
||||
@@ -507,7 +508,7 @@ let transactions = function () {
|
||||
serverUrl: urls.account,
|
||||
account_types: this.filters.destination,
|
||||
valueField: 'id',
|
||||
labelField: 'title',
|
||||
labelField: 'name_with_balance',
|
||||
onRenderItem: renderAccount,
|
||||
onChange: changeDestinationAccount,
|
||||
onSelectItem: selectDestinationAccount
|
||||
|
||||
@@ -38,16 +38,17 @@ export function addAutocomplete(options) {
|
||||
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
|
||||
}
|
||||
},
|
||||
queryParam: 'filter[query]',
|
||||
queryParam: 'query',
|
||||
hiddenInput: true,
|
||||
// preventBrowserAutocomplete: true,
|
||||
highlightTyped: true,
|
||||
liveServer: true,
|
||||
};
|
||||
if (typeof options.account_types !== 'undefined' && options.account_types.length > 0) {
|
||||
params.serverParams['filter[account_types]'] = options.account_types;
|
||||
params.serverParams['types'] = options.account_types;
|
||||
}
|
||||
if (typeof options.onRenderItem !== 'undefined' && null !== options.onRenderItem) {
|
||||
console.log('overrule onRenderItem.');
|
||||
params.onRenderItem = options.onRenderItem;
|
||||
}
|
||||
if (options.valueField) {
|
||||
|
||||
@@ -55,7 +55,7 @@ export function changeDestinationAccount(item, ac) {
|
||||
export function selectDestinationAccount(item, ac) {
|
||||
const index = parseInt(ac._searchInput.attributes['data-index'].value);
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account = {
|
||||
id: item.id, name: item.title, alpine_name: item.title, type: item.meta.type, currency_code: item.meta.currency_code,
|
||||
id: item.id, name: item.name, alpine_name: item.name, type: item.type, currency_code: item.currency_code,
|
||||
};
|
||||
document.querySelector('#form')._x_dataStack[0].changedDestinationAccount();
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export function changeSourceAccount(item, ac) {
|
||||
export function selectSourceAccount(item, ac) {
|
||||
const index = parseInt(ac._searchInput.attributes['data-index'].value);
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account = {
|
||||
id: item.id, name: item.title, alpine_name: item.title, type: item.meta.type, currency_code: item.meta.currency_code,
|
||||
id: item.id, name: item.name, alpine_name: item.name, type: item.type, currency_code: item.currency_code,
|
||||
};
|
||||
document.querySelector('#form')._x_dataStack[0].changedSourceAccount();
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export default defineConfig(({command, mode, isSsrBuild, isPreview}) => {
|
||||
|
||||
server: {
|
||||
cors: true,
|
||||
origin: 'https://firefly.sd.internal:5173',
|
||||
origin: 'https://192.168.96.154:5173',
|
||||
watch: {
|
||||
usePolling: true,
|
||||
},
|
||||
|
||||
@@ -70,7 +70,7 @@ return [
|
||||
// known user login attempt
|
||||
'failed_login_subject' => 'Firefly III detected a failed login attempt',
|
||||
'failed_login_body' => 'Firefly III detected that somebody (you?) failed to login with your account ":email". Please verify that this was you.',
|
||||
'failed_login_message' => 'A failed login attempt on your Firefly III account ":email" was detected.',
|
||||
'failed_login_message' => 'A failed login attempt (:ip) on your Firefly III account ":email" was detected.',
|
||||
'failed_login_warning' => 'If you recognize this IP address or the login attempt, you can ignore this message. If you didn\'t try to login, of if you have no idea what this is about, verify your password security, change it, and log out all other sessions. To do this, go to your profile page. Of course you have 2FA enabled already, right? Stay safe!',
|
||||
|
||||
// registered
|
||||
|
||||
@@ -2486,6 +2486,10 @@ return [
|
||||
'left_for_piggy_banks' => 'Left for piggy banks',
|
||||
'sum_of_piggy_banks' => 'Sum of piggy banks',
|
||||
'saved_so_far' => 'Saved so far',
|
||||
'saved_so_far_total' => 'Saved so far in total',
|
||||
'reset_history' => 'reset history',
|
||||
'reset_history_confirm' => 'Are you sure you want to reset the history of this piggy bank? This will make the chart match the piggy bank\'s amount again.',
|
||||
'piggy_history_reset' => 'The piggy bank history has been reset',
|
||||
'left_to_save' => 'Left to save',
|
||||
'suggested_amount' => 'Suggested monthly amount to save',
|
||||
'add_money_to_piggy_title' => 'Add money to piggy bank ":name"',
|
||||
|
||||
@@ -68,6 +68,7 @@ return [
|
||||
'cannot_find_piggy' => 'Firefly III can\'t find a piggy bank named ":name"',
|
||||
'no_link_piggy' => 'This transaction\'s accounts are not linked to the piggy bank, so no action will be taken',
|
||||
'both_link_piggy' => 'This transaction\'s accounts are both linked to the piggy bank, so no action will be taken',
|
||||
'already_linked' => 'This transaction is already linked to piggy bank ":name"',
|
||||
'cannot_unlink_tag' => 'Tag ":tag" isn\'t linked to this transaction',
|
||||
'cannot_find_budget' => 'Firefly III can\'t find budget ":name"',
|
||||
'cannot_find_category' => 'Firefly III can\'t find category ":name"',
|
||||
|
||||
@@ -163,22 +163,31 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="{{ style|raw }};text-align:right">
|
||||
|
||||
{# deposit #}
|
||||
{% if transaction.transaction_type_type == 'Deposit' %}
|
||||
{# amount of deposit #}
|
||||
{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_decimal_places) }}
|
||||
{# foreign amount of deposit #}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount*-1, transaction.foreign_currency_symbol, transaction.foreign_currency_decimal_places) }})
|
||||
{% endif %}
|
||||
{# native amount of deposit #}
|
||||
{% if convertToNative and 0 != transaction.native_amount %}
|
||||
({{ formatAmountBySymbol(transaction.native_amount*-1, defaultCurrency.symbol, defaultCurrency.decimal_places) }})
|
||||
{% endif %}
|
||||
{# transfer #}
|
||||
{% elseif transaction.transaction_type_type == 'Transfer' %}
|
||||
<span class="text-info money-transfer">
|
||||
{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_decimal_places, false) }}
|
||||
{# amount of transfer #}
|
||||
{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_decimal_places, false) }}
|
||||
|
||||
{# foreign amount of transfer #}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount*-1, transaction.foreign_currency_symbol, transaction.foreign_currency_decimal_places, false) }})
|
||||
{% endif %}
|
||||
|
||||
{# native amount of transfer #}
|
||||
{% if convertToNative and 0 != transaction.native_amount %}
|
||||
({{ formatAmountBySymbol(transaction.native_amount*-1, defaultCurrency.symbol, defaultCurrency.decimal_places) }})
|
||||
{% endif %}
|
||||
@@ -244,10 +253,14 @@
|
||||
|
||||
{# THE REST #}
|
||||
{% else %}
|
||||
{# amount of withdrawal #}
|
||||
{{ formatAmountBySymbol(transaction.amount, transaction.currency_symbol, transaction.currency_decimal_places) }}
|
||||
|
||||
{# foreign amount of withdrawal #}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_decimal_places) }})
|
||||
{% endif %}
|
||||
{# native amount of withdrawal #}
|
||||
{% if convertToNative and 0 != transaction.native_amount %}
|
||||
({{ formatAmountBySymbol(transaction.native_amount, defaultCurrency.symbol, defaultCurrency.decimal_places) }})
|
||||
{% endif %}
|
||||
|
||||
@@ -54,8 +54,20 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% for account in piggy.accounts %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ 'saved_so_far'|_ }}
|
||||
(<a href="{{ route('accounts.show', account.id) }}">{{ account.name }}</a>)
|
||||
</td>
|
||||
<td>
|
||||
{{ formatAmountBySymbol(account.current_amount, piggy.currency_symbol, piggy.currency_decimal_places) }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>{{ 'saved_so_far'|_ }}</td>
|
||||
<td>{{ 'saved_so_far_total'|_ }}</td>
|
||||
<td>
|
||||
{{ formatAmountBySymbol(piggy.current_amount, piggy.currency_symbol, piggy.currency_decimal_places) }}
|
||||
</td>
|
||||
@@ -102,7 +114,7 @@
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'event_history'|_ }}</h3>
|
||||
<h3 class="box-title">{{ 'event_history'|_ }} (<a onclick="return confirm('{{ 'reset_history_confirm'|_|escape('js') }}');" class="reset-link" href="#">{{ 'reset_history'|_ }}</a>)</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding" id="piggyEvents">
|
||||
{% include 'list/piggy-bank-events' %}
|
||||
@@ -140,6 +152,9 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<form id="reset-form" action="{{ route('piggy-banks.reset', [piggyBank.id]) }}" method="POST" style="display: none;">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<a :href="'{{ route('accounts.show', '0') }}/' + account.id"
|
||||
<a :href="'{{ route('accounts.show', '') }}/' + account.id"
|
||||
x-text="account.name"></a>
|
||||
|
||||
<span class="small">
|
||||
@@ -42,7 +42,7 @@
|
||||
<template x-if="group.transactions[0].type === 'transfer'">
|
||||
<span class="text-muted fa-solid fa-arrows-rotate fa-fw"></span>
|
||||
</template>
|
||||
<a :href="'{{route('transactions.show', '0') }}/' + group.id" x-text="group.title"></a><br/></span>
|
||||
<a :href="'{{route('transactions.show', '') }}/' + group.id" x-text="group.title"></a><br/></span>
|
||||
</template>
|
||||
<ul class="list-unstyled list-no-margin">
|
||||
<template x-for="transaction in group.transactions">
|
||||
@@ -61,7 +61,7 @@
|
||||
<template x-if="transaction.type == 'transfer'">
|
||||
<span class="text-muted fa-solid fa-arrows-rotate fa-fw"></span>
|
||||
</template>
|
||||
<a :href="'{{route('transactions.show', '0') }}/' + group.id" x-text="transaction.description"></a>
|
||||
<a :href="'{{route('transactions.show', '') }}/' + group.id" x-text="transaction.description"></a>
|
||||
</span>
|
||||
</template>
|
||||
</li>
|
||||
@@ -75,7 +75,7 @@
|
||||
<ul class="list-unstyled list-no-margin">
|
||||
<template x-for="transaction in group.transactions">
|
||||
<li>
|
||||
@include('partials.elements.amount', ['convertToNative' => true,'type' => 'transaction.type','amount' => 'transaction.amount','native' => 'transaction.native_amount'])
|
||||
@include('partials.elements.amount', ['convertToNative' => true,'type' => 'transaction.type','amount' => 'transaction.amount','native' => 'transaction.amount'])
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<template x-for="bill in group.bills">
|
||||
<tr>
|
||||
<td>
|
||||
<a :href="'{{ route('subscriptions.show',['0']) }}/' + bill.id" :title="bill.name">
|
||||
<a :href="'{{ route('subscriptions.show',['']) }}/' + bill.id" :title="bill.name">
|
||||
<span x-text="bill.name"></span>
|
||||
</a>
|
||||
<template x-if="bill.paid">
|
||||
|
||||
@@ -183,7 +183,7 @@ Route::group(
|
||||
|
||||
// show
|
||||
Route::get('show/{account}/all', ['uses' => 'Account\ShowController@showAll', 'as' => 'show.all']);
|
||||
Route::get('show/{account}/{start_date?}/{end_date?}', ['uses' => 'Account\ShowController@show', 'as' => 'show'])
|
||||
Route::get('show/{account?}/{start_date?}/{end_date?}', ['uses' => 'Account\ShowController@show', 'as' => 'show'])
|
||||
->where(['start_date' => DATEFORMAT])
|
||||
->where(['end_date' => DATEFORMAT])
|
||||
;
|
||||
@@ -255,7 +255,7 @@ Route::group(
|
||||
Route::get('create', ['uses' => 'Bill\CreateController@create', 'as' => 'create']);
|
||||
Route::get('edit/{bill}', ['uses' => 'Bill\EditController@edit', 'as' => 'edit']);
|
||||
Route::get('delete/{bill}', ['uses' => 'Bill\DeleteController@delete', 'as' => 'delete']);
|
||||
Route::get('show/{bill}', ['uses' => 'Bill\ShowController@show', 'as' => 'show']);
|
||||
Route::get('show/{bill?}', ['uses' => 'Bill\ShowController@show', 'as' => 'show']);
|
||||
|
||||
Route::post('store', ['uses' => 'Bill\CreateController@store', 'as' => 'store']);
|
||||
Route::post('update/{bill}', ['uses' => 'Bill\EditController@update', 'as' => 'update']);
|
||||
@@ -803,6 +803,7 @@ Route::group(
|
||||
Route::post('store', ['uses' => 'PiggyBank\CreateController@store', 'as' => 'store']);
|
||||
Route::post('update/{piggyBank}', ['uses' => 'PiggyBank\EditController@update', 'as' => 'update']);
|
||||
Route::post('destroy/{piggyBank}', ['uses' => 'PiggyBank\DeleteController@destroy', 'as' => 'destroy']);
|
||||
Route::post('reset-history/{piggyBank}', ['uses' => 'PiggyBank\EditController@resetHistory', 'as' => 'reset']);
|
||||
Route::post('add/{piggyBank}', ['uses' => 'PiggyBank\AmountController@postAdd', 'as' => 'add']);
|
||||
Route::post('remove/{piggyBank}', ['uses' => 'PiggyBank\AmountController@postRemove', 'as' => 'remove']);
|
||||
|
||||
@@ -1295,7 +1296,7 @@ Route::group(
|
||||
// unreconcile
|
||||
Route::post('unreconcile/{tj}', ['uses' => 'Transaction\EditController@unreconcile', 'as' => 'unreconcile']);
|
||||
|
||||
Route::get('show/{transactionGroup}', ['uses' => 'Transaction\ShowController@show', 'as' => 'show']);
|
||||
Route::get('show/{transactionGroup?}', ['uses' => 'Transaction\ShowController@show', 'as' => 'show']);
|
||||
Route::get('debug/{transactionGroup}', ['uses' => 'Transaction\ShowController@debugShow', 'as' => 'debug']);
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user