Merge branch 'develop' into 5.8-dev

# Conflicts:
#	app/Factory/TransactionJournalFactory.php
#	app/Providers/EventServiceProvider.php
#	app/Repositories/PiggyBank/ModifiesPiggyBanks.php
#	app/Support/Search/OperatorQuerySearch.php
#	app/Support/Steam.php
#	app/TransactionRules/Actions/UpdatePiggybank.php
#	composer.json
#	composer.lock
#	config/search.php
#	frontend/yarn.lock
#	resources/lang/en_US/firefly.php
This commit is contained in:
James Cole
2022-12-11 07:37:33 +01:00
30 changed files with 802 additions and 640 deletions

View File

@@ -243,7 +243,7 @@ ALLOW_WEBHOOKS=false
STATIC_CRON_TOKEN= STATIC_CRON_TOKEN=
# You can fine tune the start-up of a Docker container by editing these environment variables. # You can fine tune the start-up of a Docker container by editing these environment variables.
# Use this at your own risk. Disabling certain checks and features may result in lost of inconsistent data. # Use this at your own risk. Disabling certain checks and features may result in lots of inconsistent data.
# However if you know what you're doing you can significantly speed up container start times. # However if you know what you're doing you can significantly speed up container start times.
# Set each value to true to enable, or false to disable. # Set each value to true to enable, or false to disable.

2
.github/security.md vendored
View File

@@ -40,7 +40,7 @@ The Firefly III developer will respond to vulnerability reports as follows:
9. Once the fix is confirmed, the developer will patch the vulnerability in the next patch or minor release. Upon release of the patched version of Firefly III, we will follow the **Public Disclosure Process**. 9. Once the fix is confirmed, the developer will patch the vulnerability in the next patch or minor release. Upon release of the patched version of Firefly III, we will follow the **Public Disclosure Process**.
### Public Disclosure Process ### Public Disclosure Process
The developer publishes a public [advisory](https://github.com/firefly-iii/firefly-iii/security/advisories) to the Firefly III community via GitHub. In most cases, additional communication via Twitter, reddit and other channels will assist in educating Firefly III users and rolling out the patched release to affected users. The developer publishes a public [advisory](https://github.com/firefly-iii/firefly-iii/security/advisories) to the Firefly III community via GitHub. In most cases, additional communication via Mastodon, Gitter and other channels will assist in educating Firefly III users and rolling out the patched release to affected users.
The develop will also publish any mitigating steps users can take until the fix can be applied to their Firefly III instances. The develop will also publish any mitigating steps users can take until the fix can be applied to their Firefly III instances.

View File

@@ -2,6 +2,7 @@ name: "Close stale issues"
on: on:
schedule: schedule:
- cron: "30 1 * * *" - cron: "30 1 * * *"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@@ -13,7 +14,7 @@ jobs:
pull-requests: write # for actions/stale to close stale PRs pull-requests: write # for actions/stale to close stale PRs
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v3 - uses: actions/stale@v6
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: > stale-issue-message: >

View File

@@ -0,0 +1,58 @@
<?php
/*
* ChangedPiggyBankAmount.php
* Copyright (c) 2022 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Events;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
/**
* Class ChangedPiggyBankAmount
*/
class ChangedPiggyBankAmount extends Event
{
use SerializesModels;
public PiggyBank $piggyBank;
public ?TransactionJournal $transactionJournal;
public ?TransactionGroup $transactionGroup;
public string $amount;
/**
* Create a new event instance.
*
* @param PiggyBank $piggyBank
* @param string $amount
* @param TransactionJournal|null $transactionJournal
* @param TransactionGroup|null $transactionGroup
*/
public function __construct(PiggyBank $piggyBank, string $amount, ?TransactionJournal $transactionJournal, ?TransactionGroup $transactionGroup)
{
Log::debug(sprintf('Created piggy bank event for piggy bank #%d with amount %s', $piggyBank->id, $amount));
$this->piggyBank = $piggyBank;
$this->transactionJournal = $transactionJournal;
$this->transactionGroup = $transactionGroup;
$this->amount = $amount;
}
}

View File

@@ -22,6 +22,7 @@ declare(strict_types=1);
namespace FireflyIII\Factory; namespace FireflyIII\Factory;
use FireflyIII\Events\ChangedPiggyBankAmount;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent; use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -39,22 +40,20 @@ class PiggyBankEventFactory
/** /**
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param PiggyBank|null $piggyBank * @param PiggyBank|null $piggyBank
*
* @return PiggyBankEvent|null
*/ */
public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): ?PiggyBankEvent public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): void
{ {
Log::debug(sprintf('Now in PiggyBankEventCreate for a %s', $journal->transactionType->type)); Log::debug(sprintf('Now in PiggyBankEventCreate for a %s', $journal->transactionType->type));
if (null === $piggyBank) { if (null === $piggyBank) {
Log::debug('Piggy bank is null'); Log::debug('Piggy bank is null');
return null; return;
} }
if (TransactionType::TRANSFER !== $journal->transactionType->type) { if (TransactionType::TRANSFER !== $journal->transactionType->type) {
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id)); Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
return null; return;
} }
/** @var PiggyBankRepositoryInterface $piggyRepos */ /** @var PiggyBankRepositoryInterface $piggyRepos */
@@ -65,20 +64,16 @@ class PiggyBankEventFactory
if (null === $repetition) { if (null === $repetition) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d'))); Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
return null; return;
} }
Log::debug('Found repetition'); Log::debug('Found repetition');
$amount = $piggyRepos->getExactAmount($piggyBank, $repetition, $journal); $amount = $piggyRepos->getExactAmount($piggyBank, $repetition, $journal);
if (0 === bccomp($amount, '0')) { if (0 === bccomp($amount, '0')) {
Log::debug('Amount is zero, will not create event.'); Log::debug('Amount is zero, will not create event.');
return null; return;
} }
// amount can be negative here
$piggyRepos->addAmountToRepetition($repetition, $amount); $piggyRepos->addAmountToRepetition($repetition, $amount, $journal);
$event = $piggyRepos->createEventWithJournal($piggyBank, $amount, $journal);
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
return $event;
} }
} }

View File

@@ -93,7 +93,7 @@ class TransactionJournalFactory
/** /**
* Store a new (set of) transaction journals. * Store a new (set of) transaction journals.
* *
* @param array $data * @param array $data
* *
* @return Collection * @return Collection
* @throws DuplicateTransactionException * @throws DuplicateTransactionException
@@ -144,7 +144,7 @@ class TransactionJournalFactory
} }
/** /**
* @param NullArrayObject $row * @param NullArrayObject $row
* *
* @return TransactionJournal|null * @return TransactionJournal|null
* @throws DuplicateTransactionException * @throws DuplicateTransactionException
@@ -161,11 +161,11 @@ class TransactionJournalFactory
$type = $this->typeRepository->findTransactionType(null, $row['type']); $type = $this->typeRepository->findTransactionType(null, $row['type']);
$carbon = $row['date'] ?? today(config('app.timezone')); $carbon = $row['date'] ?? today(config('app.timezone'));
$order = $row['order'] ?? 0; $order = $row['order'] ?? 0;
$currency = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']); $currency = $this->currencyRepository->findCurrency((int)$row['currency_id'], $row['currency_code']);
$foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']); $foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']);
$bill = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']); $bill = $this->billRepository->findBill((int)$row['bill_id'], $row['bill_name']);
$billId = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null; $billId = TransactionType::WITHDRAWAL === $type->type && null !== $bill ? $bill->id : null;
$description = (string) $row['description']; $description = (string)$row['description'];
/** Manipulate basic fields */ /** Manipulate basic fields */
$carbon->setTimezone(config('app.timezone')); $carbon->setTimezone(config('app.timezone'));
@@ -244,7 +244,7 @@ class TransactionJournalFactory
$transactionFactory->setForeignCurrency($foreignCurrency); $transactionFactory->setForeignCurrency($foreignCurrency);
$transactionFactory->setReconciled($row['reconciled'] ?? false); $transactionFactory->setReconciled($row['reconciled'] ?? false);
try { try {
$negative = $transactionFactory->createNegative((string) $row['amount'], (string) $row['foreign_amount']); $negative = $transactionFactory->createNegative((string)$row['amount'], (string)$row['foreign_amount']);
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error('Exception creating negative transaction.'); Log::error('Exception creating negative transaction.');
Log::error($e->getMessage()); Log::error($e->getMessage());
@@ -263,7 +263,7 @@ class TransactionJournalFactory
$transactionFactory->setForeignCurrency($foreignCurrency); $transactionFactory->setForeignCurrency($foreignCurrency);
$transactionFactory->setReconciled($row['reconciled'] ?? false); $transactionFactory->setReconciled($row['reconciled'] ?? false);
try { try {
$transactionFactory->createPositive((string) $row['amount'], (string) $row['foreign_amount']); $transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']);
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error('Exception creating positive transaction.'); Log::error('Exception creating positive transaction.');
Log::error($e->getMessage()); Log::error($e->getMessage());
@@ -301,7 +301,7 @@ class TransactionJournalFactory
} }
/** /**
* @param NullArrayObject $row * @param NullArrayObject $row
* *
* @return string * @return string
* @throws JsonException * @throws JsonException
@@ -325,7 +325,7 @@ class TransactionJournalFactory
/** /**
* If this transaction already exists, throw an error. * If this transaction already exists, throw an error.
* *
* @param string $hash * @param string $hash
* *
* @throws DuplicateTransactionException * @throws DuplicateTransactionException
* @throws JsonException * @throws JsonException
@@ -358,7 +358,7 @@ class TransactionJournalFactory
} }
/** /**
* @param NullArrayObject $data * @param NullArrayObject $data
* *
* @throws FireflyException * @throws FireflyException
*/ */
@@ -371,10 +371,10 @@ class TransactionJournalFactory
// validate source account. // validate source account.
$array = [ $array = [
'id' => $data['source_id'] ? (int) $data['source_id'] : null, 'id' => $data['source_id'] ? (int)$data['source_id'] : null,
'name' => $data['source_name'] ? (string) $data['source_name'] : null, 'name' => $data['source_name'] ? (string)$data['source_name'] : null,
'iban' => $data['source_iban'] ? (string) $data['source_iban'] : null, 'iban' => $data['source_iban'] ? (string)$data['source_iban'] : null,
'number' => $data['source_number'] ? (string) $data['source_number'] : null, 'number' => $data['source_number'] ? (string)$data['source_number'] : null,
]; ];
$validSource = $this->accountValidator->validateSource($array); $validSource = $this->accountValidator->validateSource($array);
@@ -386,10 +386,10 @@ class TransactionJournalFactory
// validate destination account // validate destination account
$array = [ $array = [
'id' => $data['destination_id'] ? (int) $data['destination_id'] : null, 'id' => $data['destination_id'] ? (int)$data['destination_id'] : null,
'name' => $data['destination_name'] ? (string) $data['destination_name'] : null, 'name' => $data['destination_name'] ? (string)$data['destination_name'] : null,
'iban' => $data['destination_iban'] ? (string) $data['destination_iban'] : null, 'iban' => $data['destination_iban'] ? (string)$data['destination_iban'] : null,
'number' => $data['destination_number'] ? (string) $data['destination_number'] : null, 'number' => $data['destination_number'] ? (string)$data['destination_number'] : null,
]; ];
$validDestination = $this->accountValidator->validateDestination($array); $validDestination = $this->accountValidator->validateDestination($array);
@@ -400,10 +400,10 @@ class TransactionJournalFactory
} }
/** /**
* @param string $type * @param string $type
* @param TransactionCurrency|null $currency * @param TransactionCurrency|null $currency
* @param Account $source * @param Account $source
* @param Account $destination * @param Account $destination
* *
* @return TransactionCurrency * @return TransactionCurrency
*/ */
@@ -418,8 +418,8 @@ class TransactionJournalFactory
} }
/** /**
* @param TransactionCurrency|null $currency * @param TransactionCurrency|null $currency
* @param Account $account * @param Account $account
* *
* @return TransactionCurrency * @return TransactionCurrency
* @throws FireflyException * @throws FireflyException
@@ -442,8 +442,8 @@ class TransactionJournalFactory
/** /**
* Set foreign currency to NULL if it's the same as the normal currency: * Set foreign currency to NULL if it's the same as the normal currency:
* *
* @param TransactionCurrency|null $currency * @param TransactionCurrency|null $currency
* @param TransactionCurrency|null $foreignCurrency * @param TransactionCurrency|null $foreignCurrency
* *
* @return TransactionCurrency|null * @return TransactionCurrency|null
*/ */
@@ -460,9 +460,9 @@ class TransactionJournalFactory
} }
/** /**
* @param string $type * @param string $type
* @param TransactionCurrency|null $foreignCurrency * @param TransactionCurrency|null $foreignCurrency
* @param Account $destination * @param Account $destination
* *
* @return TransactionCurrency|null * @return TransactionCurrency|null
*/ */
@@ -476,7 +476,7 @@ class TransactionJournalFactory
} }
/** /**
* @param string $description * @param string $description
* *
* @return string * @return string
*/ */
@@ -491,7 +491,7 @@ class TransactionJournalFactory
* Force the deletion of an entire set of transaction journals and their meta object in case of * Force the deletion of an entire set of transaction journals and their meta object in case of
* an error creating a group. * an error creating a group.
* *
* @param Collection $collection * @param Collection $collection
*/ */
private function forceDeleteOnError(Collection $collection): void private function forceDeleteOnError(Collection $collection): void
{ {
@@ -505,7 +505,7 @@ class TransactionJournalFactory
} }
/** /**
* @param Transaction $transaction * @param Transaction $transaction
*/ */
private function forceTrDelete(Transaction $transaction): void private function forceTrDelete(Transaction $transaction): void
{ {
@@ -521,8 +521,8 @@ class TransactionJournalFactory
/** /**
* Link a piggy bank to this journal. * Link a piggy bank to this journal.
* *
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param NullArrayObject $data * @param NullArrayObject $data
*/ */
private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void
{ {
@@ -533,7 +533,7 @@ class TransactionJournalFactory
return; return;
} }
$piggyBank = $this->piggyRepository->findPiggyBank((int) $data['piggy_bank_id'], $data['piggy_bank_name']); $piggyBank = $this->piggyRepository->findPiggyBank((int)$data['piggy_bank_id'], $data['piggy_bank_name']);
if (null !== $piggyBank) { if (null !== $piggyBank) {
$this->piggyEventFactory->create($journal, $piggyBank); $this->piggyEventFactory->create($journal, $piggyBank);
@@ -545,8 +545,8 @@ class TransactionJournalFactory
} }
/** /**
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param NullArrayObject $transaction * @param NullArrayObject $transaction
*/ */
private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
{ {
@@ -556,16 +556,16 @@ class TransactionJournalFactory
} }
/** /**
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param NullArrayObject $data * @param NullArrayObject $data
* @param string $field * @param string $field
*/ */
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
{ {
$set = [ $set = [
'journal' => $journal, 'journal' => $journal,
'name' => $field, 'name' => $field,
'data' => (string) ($data[$field] ?? ''), 'data' => (string)($data[$field] ?? ''),
]; ];
//Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data'])); //Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data']));
@@ -576,7 +576,7 @@ class TransactionJournalFactory
} }
/** /**
* @param bool $errorOnHash * @param bool $errorOnHash
*/ */
public function setErrorOnHash(bool $errorOnHash): void public function setErrorOnHash(bool $errorOnHash): void
{ {
@@ -589,7 +589,7 @@ class TransactionJournalFactory
/** /**
* Set the user. * Set the user.
* *
* @param User $user * @param User $user
*/ */
public function setUser(User $user): void public function setUser(User $user): void
{ {

View File

@@ -0,0 +1,69 @@
<?php
/*
* PiggyBankEventHandler.php
* Copyright (c) 2022 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Handlers\Events;
use Carbon\Carbon;
use FireflyIII\Events\ChangedPiggyBankAmount;
use FireflyIII\Models\PiggyBankEvent;
use Illuminate\Support\Facades\Log;
/**
* Class PiggyBankEventHandler
*/
class PiggyBankEventHandler
{
/**
* @param ChangedPiggyBankAmount $event
* @return void
*/
public function changePiggyAmount(ChangedPiggyBankAmount $event): void
{
// find journal if group is present.
$journal = $event->transactionJournal;
if (null !== $event->transactionGroup) {
$journal = $event->transactionGroup->transactionJournals()->first();
}
$date = $journal?->date ?? Carbon::now();
// sanity check: event must not already exist for this journal and piggy bank.
if (null !== $journal) {
$exists = PiggyBankEvent::where('piggy_bank_id', $event->piggyBank->id)
->where('transaction_journal_id', $journal->id)
->exists();
if($exists) {
Log::warning('Already have event for this journal and piggy, will not create another.');
return;
}
}
PiggyBankEvent::create(
[
'piggy_bank_id' => $event->piggyBank->id,
'transaction_journal_id' => $journal?->id,
'date' => $date->format('Y-m-d'),
'amount' => $event->amount,
]
);
}
}

View File

@@ -98,6 +98,7 @@ trait AttachmentCollection
Log::debug('Add filter on attachment ID.'); Log::debug('Add filter on attachment ID.');
$this->joinAttachmentTables(); $this->joinAttachmentTables();
$this->query->whereNotNull('attachments.attachable_id'); $this->query->whereNotNull('attachments.attachable_id');
$this->query->whereNull('attachments.deleted_at');
return $this; return $this;
} }

View File

@@ -1015,4 +1015,17 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function setSepaCT(string $sepaCT): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'sepa_ct_id');
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($sepaCT)));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
} }

View File

@@ -128,7 +128,6 @@ class AmountController extends Controller
} }
if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) { if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) {
$this->piggyRepos->addAmount($piggyBank, $amount); $this->piggyRepos->addAmount($piggyBank, $amount);
$this->piggyRepos->createEvent($piggyBank, $amount);
session()->flash( session()->flash(
'success', 'success',
(string) trans( (string) trans(

View File

@@ -26,6 +26,7 @@ use Exception;
use FireflyIII\Events\ActuallyLoggedIn; use FireflyIII\Events\ActuallyLoggedIn;
use FireflyIII\Events\Admin\InvitationCreated; use FireflyIII\Events\Admin\InvitationCreated;
use FireflyIII\Events\AdminRequestedTestMessage; use FireflyIII\Events\AdminRequestedTestMessage;
use FireflyIII\Events\ChangedPiggyBankAmount;
use FireflyIII\Events\DestroyedTransactionGroup; use FireflyIII\Events\DestroyedTransactionGroup;
use FireflyIII\Events\DetectedNewIPAddress; use FireflyIII\Events\DetectedNewIPAddress;
use FireflyIII\Events\NewVersionAvailable; use FireflyIII\Events\NewVersionAvailable;
@@ -162,6 +163,10 @@ class EventServiceProvider extends ServiceProvider
// audit log events: // audit log events:
TriggeredAuditLog::class => [ TriggeredAuditLog::class => [
'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent', 'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent',
// piggy bank related events:
ChangedPiggyBankAmount::class => [
'FireflyIII\Handlers\Events\PiggyBankEventHandler@changePiggyAmount',
], ],
]; ];

View File

@@ -24,17 +24,16 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\PiggyBank; namespace FireflyIII\Repositories\PiggyBank;
use Carbon\Carbon;
use Exception; use Exception;
use FireflyIII\Events\ChangedPiggyBankAmount;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups; use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Log; use Illuminate\Support\Facades\Log;
/** /**
* Trait ModifiesPiggyBanks * Trait ModifiesPiggyBanks
@@ -44,12 +43,12 @@ trait ModifiesPiggyBanks
use CreatesObjectGroups; use CreatesObjectGroups;
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* * @param TransactionJournal|null $journal
* @return bool * @return bool
*/ */
public function addAmount(PiggyBank $piggyBank, string $amount): bool public function addAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool
{ {
$repetition = $this->getRepetition($piggyBank); $repetition = $this->getRepetition($piggyBank);
if (null === $repetition) { if (null === $repetition) {
@@ -59,30 +58,34 @@ trait ModifiesPiggyBanks
$repetition->currentamount = bcadd($currentAmount, $amount); $repetition->currentamount = bcadd($currentAmount, $amount);
$repetition->save(); $repetition->save();
// create event Log::debug('addAmount: Trigger change for positive amount.');
//$this->createEvent($piggyBank, $amount); event(new ChangedPiggyBankAmount($piggyBank, $amount, $journal, null));
return true; return true;
} }
/** /**
* @param PiggyBankRepetition $repetition * @param PiggyBankRepetition $repetition
* @param string $amount * @param string $amount
* *
* @return string * @return void
*/ */
public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount): string public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount, TransactionJournal $journal): void
{ {
$newAmount = bcadd($repetition->currentamount, $amount); Log::debug(sprintf('addAmountToRepetition: %s', $amount));
$repetition->currentamount = $newAmount; if (-1 === bccomp($amount, '0')) {
$repetition->save(); Log::debug('Remove amount.');
$this->removeAmount($repetition->piggyBank, bcmul($amount, '-1'), $journal);
return $newAmount; }
if (1 === bccomp($amount, '0')) {
Log::debug('Add amount.');
$this->addAmount($repetition->piggyBank, $amount, $journal);
}
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* *
* @return bool * @return bool
*/ */
@@ -90,10 +93,10 @@ trait ModifiesPiggyBanks
{ {
$today = today(config('app.timezone')); $today = today(config('app.timezone'));
$leftOnAccount = $this->leftOnAccount($piggyBank, $today); $leftOnAccount = $this->leftOnAccount($piggyBank, $today);
$savedSoFar = (string) $this->getRepetition($piggyBank)->currentamount; $savedSoFar = (string)$this->getRepetition($piggyBank)->currentamount;
$maxAmount = $leftOnAccount; $maxAmount = $leftOnAccount;
$leftToSave = null; $leftToSave = null;
if (0.0 !== (float) $piggyBank->targetamount) { if (0.0 !== (float)$piggyBank->targetamount) {
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar); $leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = 1 === bccomp($leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount; $maxAmount = 1 === bccomp($leftOnAccount, $leftToSave) ? $leftToSave : $leftOnAccount;
} }
@@ -111,8 +114,8 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* *
* @return bool * @return bool
*/ */
@@ -128,25 +131,7 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount
* @param TransactionJournal $journal
*
* @return PiggyBankEvent
*/
public function createEventWithJournal(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): PiggyBankEvent
{
return PiggyBankEvent::create(
[
'piggy_bank_id' => $piggyBank->id,
'transaction_journal_id' => $journal->id,
'date' => $journal->date->format('Y-m-d'),
'amount' => $amount]
);
}
/**
* @param PiggyBank $piggyBank
* *
* @return bool * @return bool
* @throws Exception * @throws Exception
@@ -160,12 +145,12 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* *
* @return bool * @return bool
*/ */
public function removeAmount(PiggyBank $piggyBank, string $amount): bool public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool
{ {
$repetition = $this->getRepetition($piggyBank); $repetition = $this->getRepetition($piggyBank);
if (null === $repetition) { if (null === $repetition) {
@@ -174,27 +159,12 @@ trait ModifiesPiggyBanks
$repetition->currentamount = bcsub($repetition->currentamount, $amount); $repetition->currentamount = bcsub($repetition->currentamount, $amount);
$repetition->save(); $repetition->save();
// create event Log::debug('addAmount: Trigger change for negative amount.');
$this->createEvent($piggyBank, bcmul($amount, '-1')); event(new ChangedPiggyBankAmount($piggyBank, bcmul($amount, '-1'), $journal, null));
return true; return true;
} }
/**
* @param PiggyBank $piggyBank
* @param string $amount
*
* @return PiggyBankEvent
*/
public function createEvent(PiggyBank $piggyBank, string $amount): PiggyBankEvent
{
if (0 === bccomp('0', $amount)) {
return new PiggyBankEvent();
}
return PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -206,8 +176,8 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* *
* @return PiggyBank * @return PiggyBank
*/ */
@@ -225,8 +195,14 @@ trait ModifiesPiggyBanks
$repetition->currentamount = $amount; $repetition->currentamount = $amount;
$repetition->save(); $repetition->save();
// create event if (-1 === bccomp($difference, '0')) {
$this->createEvent($piggyBank, $difference); Log::debug('addAmount: Trigger change for negative amount.');
event(new ChangedPiggyBankAmount($piggyBank, bcmul($amount, '-1'), null, null));
}
if (1 === bccomp($difference, '0')) {
Log::debug('addAmount: Trigger change for positive amount.');
event(new ChangedPiggyBankAmount($piggyBank, $amount, null, null));
}
return $piggyBank; return $piggyBank;
} }
@@ -245,7 +221,7 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param array $data * @param array $data
* *
* @return PiggyBank * @return PiggyBank
* @throws FireflyException * @throws FireflyException
@@ -262,7 +238,7 @@ trait ModifiesPiggyBanks
unset($piggyData['object_group_title'], $piggyData['object_group_id'], $piggyData['notes'], $piggyData['current_amount']); unset($piggyData['object_group_title'], $piggyData['object_group_id'], $piggyData['notes'], $piggyData['current_amount']);
// validate amount: // validate amount:
if (array_key_exists('targetamount', $piggyData) && '' === (string) $piggyData['targetamount']) { if (array_key_exists('targetamount', $piggyData) && '' === (string)$piggyData['targetamount']) {
$piggyData['targetamount'] = '0'; $piggyData['targetamount'] = '0';
} }
@@ -296,7 +272,7 @@ trait ModifiesPiggyBanks
} }
} }
// try also with ID // try also with ID
$objectGroupId = (int) ($data['object_group_id'] ?? 0); $objectGroupId = (int)($data['object_group_id'] ?? 0);
if (0 !== $objectGroupId) { if (0 !== $objectGroupId) {
$objectGroup = $this->findObjectGroupById($objectGroupId); $objectGroup = $this->findObjectGroupById($objectGroupId);
if (null !== $objectGroup) { if (null !== $objectGroup) {
@@ -316,7 +292,7 @@ trait ModifiesPiggyBanks
$set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); $set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']);
$current = 1; $current = 1;
foreach ($set as $piggyBank) { foreach ($set as $piggyBank) {
if ((int) $piggyBank->order !== $current) { if ((int)$piggyBank->order !== $current) {
Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current)); Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current));
$piggyBank->order = $current; $piggyBank->order = $current;
$piggyBank->save(); $piggyBank->save();
@@ -330,7 +306,7 @@ trait ModifiesPiggyBanks
*/ */
public function setOrder(PiggyBank $piggyBank, int $newOrder): bool public function setOrder(PiggyBank $piggyBank, int $newOrder): bool
{ {
$oldOrder = (int) $piggyBank->order; $oldOrder = (int)$piggyBank->order;
Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder)); Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
if ($newOrder > $oldOrder) { if ($newOrder > $oldOrder) {
$this->user->piggyBanks()->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder) $this->user->piggyBanks()->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
@@ -354,8 +330,8 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $note * @param string $note
* *
* @return bool * @return bool
*/ */
@@ -385,8 +361,8 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param array $data * @param array $data
* *
* @return PiggyBank * @return PiggyBank
*/ */
@@ -394,12 +370,12 @@ trait ModifiesPiggyBanks
{ {
$piggyBank = $this->updateProperties($piggyBank, $data); $piggyBank = $this->updateProperties($piggyBank, $data);
if (array_key_exists('notes', $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: // update the order of the piggy bank:
$oldOrder = (int) $piggyBank->order; $oldOrder = (int)$piggyBank->order;
$newOrder = (int) ($data['order'] ?? $oldOrder); $newOrder = (int)($data['order'] ?? $oldOrder);
if ($oldOrder !== $newOrder) { if ($oldOrder !== $newOrder) {
$this->setOrder($piggyBank, $newOrder); $this->setOrder($piggyBank, $newOrder);
} }
@@ -407,9 +383,11 @@ trait ModifiesPiggyBanks
// if the piggy bank is now smaller than the current relevant rep, // if the piggy bank is now smaller than the current relevant rep,
// remove money from the rep. // remove money from the rep.
$repetition = $this->getRepetition($piggyBank); $repetition = $this->getRepetition($piggyBank);
if (null !== $repetition && $repetition->currentamount > $piggyBank->targetamount && 0.0 !== (float) $piggyBank->targetamount) { if (null !== $repetition && $repetition->currentamount > $piggyBank->targetamount && 0.0 !== (float)$piggyBank->targetamount) {
$diff = bcsub($piggyBank->targetamount, $repetition->currentamount); $difference = bcsub($piggyBank->targetamount, $repetition->currentamount);
$this->createEvent($piggyBank, $diff);
// an amount will be removed, create "negative" event:
event(new ChangedPiggyBankAmount($piggyBank, $difference, null, null));
$repetition->currentamount = $piggyBank->targetamount; $repetition->currentamount = $piggyBank->targetamount;
$repetition->save(); $repetition->save();
@@ -417,7 +395,7 @@ trait ModifiesPiggyBanks
// update using name: // update using name:
if (array_key_exists('object_group_title', $data)) { if (array_key_exists('object_group_title', $data)) {
$objectGroupTitle = (string) $data['object_group_title']; $objectGroupTitle = (string)$data['object_group_title'];
if ('' !== $objectGroupTitle) { if ('' !== $objectGroupTitle) {
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
if (null !== $objectGroup) { if (null !== $objectGroup) {
@@ -436,7 +414,7 @@ trait ModifiesPiggyBanks
// try also with ID: // try also with ID:
if (array_key_exists('object_group_id', $data)) { 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) { if (0 !== $objectGroupId) {
$objectGroup = $this->findObjectGroupById($objectGroupId); $objectGroup = $this->findObjectGroupById($objectGroupId);
if (null !== $objectGroup) { if (null !== $objectGroup) {
@@ -452,8 +430,8 @@ trait ModifiesPiggyBanks
} }
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param array $data * @param array $data
* *
* @return PiggyBank * @return PiggyBank
*/ */
@@ -463,7 +441,7 @@ trait ModifiesPiggyBanks
$piggyBank->name = $data['name']; $piggyBank->name = $data['name'];
} }
if (array_key_exists('account_id', $data) && 0 !== $data['account_id']) { if (array_key_exists('account_id', $data) && 0 !== $data['account_id']) {
$piggyBank->account_id = (int) $data['account_id']; $piggyBank->account_id = (int)$data['account_id'];
} }
if (array_key_exists('targetamount', $data) && '' !== $data['targetamount']) { if (array_key_exists('targetamount', $data) && '' !== $data['targetamount']) {
$piggyBank->targetamount = $data['targetamount']; $piggyBank->targetamount = $data['targetamount'];

View File

@@ -37,20 +37,18 @@ use Illuminate\Support\Collection;
interface PiggyBankRepositoryInterface interface PiggyBankRepositoryInterface
{ {
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* * @param TransactionJournal|null $journal
* @return bool * @return bool
*/ */
public function addAmount(PiggyBank $piggyBank, string $amount): bool; public function addAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool;
/** /**
* @param PiggyBankRepetition $repetition * @param PiggyBankRepetition $repetition
* @param string $amount * @param string $amount
*
* @return string
*/ */
public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount): string; public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount, TransactionJournal $journal): void;
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
@@ -68,25 +66,6 @@ interface PiggyBankRepositoryInterface
*/ */
public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool; public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool;
/**
* Create a new event.
*
* @param PiggyBank $piggyBank
* @param string $amount
*
* @return PiggyBankEvent
*/
public function createEvent(PiggyBank $piggyBank, string $amount): PiggyBankEvent;
/**
* @param PiggyBank $piggyBank
* @param string $amount
* @param TransactionJournal $journal
*
* @return PiggyBankEvent
*/
public function createEventWithJournal(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): PiggyBankEvent;
/** /**
* Destroy piggy bank. * Destroy piggy bank.
* *
@@ -218,12 +197,12 @@ interface PiggyBankRepositoryInterface
public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string; public function leftOnAccount(PiggyBank $piggyBank, Carbon $date): string;
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* @param string $amount * @param string $amount
* * @param TransactionJournal|null $journal
* @return bool * @return bool
*/ */
public function removeAmount(PiggyBank $piggyBank, string $amount): bool; public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool;
/** /**
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank

View File

@@ -83,6 +83,7 @@ class JournalDestroyService
$journal->notes()->delete(); $journal->notes()->delete();
// update events // update events
// TODO move to repository
$journal->piggyBankEvents()->update(['transaction_journal_id' => null]); $journal->piggyBankEvents()->update(['transaction_journal_id' => null]);
$journal->delete(); $journal->delete();

View File

@@ -105,7 +105,7 @@ class GroupCloneService
// add note saying "cloned". // add note saying "cloned".
// add relation. // add relation.
// clone linked piggy banks // TODO clone ALL linked piggy banks
/** @var PiggyBankEvent $event */ /** @var PiggyBankEvent $event */
$event = $journal->piggyBankEvents()->first(); $event = $journal->piggyBankEvents()->first();
if (null !== $event) { if (null !== $event) {

View File

@@ -68,6 +68,7 @@ class RemoteUserGuard implements Guard
// Get the user identifier from $_SERVER or apache filtered headers // Get the user identifier from $_SERVER or apache filtered headers
$header = config('auth.guard_header', 'REMOTE_USER'); $header = config('auth.guard_header', 'REMOTE_USER');
$userID = request()->server($header) ?? apache_request_headers()[$header] ?? null; $userID = request()->server($header) ?? apache_request_headers()[$header] ?? null;
if (null === $userID) { if (null === $userID) {
Log::error(sprintf('No user in header "%s".', $header)); Log::error(sprintf('No user in header "%s".', $header));
throw new FireflyException('The guard header was unexpectedly empty. See the logs.'); throw new FireflyException('The guard header was unexpectedly empty. See the logs.');
@@ -80,10 +81,14 @@ class RemoteUserGuard implements Guard
$header = config('auth.guard_email'); $header = config('auth.guard_email');
if (null !== $header) { if (null !== $header) {
$emailAddress = (string) (request()->server($header) ?? null); $emailAddress = (string) (request()->server($header) ?? apache_request_headers()[$header] ?? null);
$preference = app('preferences')->getForUser($retrievedUser, 'remote_guard_alt_email'); $preference = app('preferences')->getForUser($retrievedUser, 'remote_guard_alt_email');
if (null !== $emailAddress && null === $preference && $emailAddress !== $userID) { if ('' !== $emailAddress && null === $preference && $emailAddress !== $userID) {
app('preferences')->setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress);
}
// if the pref isn't null and the object returned isn't null, update the email address.
if ('' !== $emailAddress && null !== $preference && $emailAddress !== $preference->data) {
app('preferences')->setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress); app('preferences')->setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress);
} }
} }

View File

@@ -1309,6 +1309,9 @@ class OperatorQuerySearch implements SearchInterface
case '-exists': case '-exists':
$this->collector->findNothing(); $this->collector->findNothing();
break; break;
case 'sepa_ct_is':
$this->collector->setSepaCT($value);
break;
} }
return true; return true;
} }

View File

@@ -51,14 +51,6 @@ class Steam
*/ */
public function balanceIgnoreVirtual(Account $account, Carbon $date): string public function balanceIgnoreVirtual(Account $account, Carbon $date): string
{ {
// abuse chart properties:
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance-no-virtual');
$cache->addProperty($date);
if ($cache->has()) {
return $cache->get();
}
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user); $repository->setUser($account->user);
@@ -80,11 +72,7 @@ class Steam
->get(['transactions.foreign_amount'])->toArray(); ->get(['transactions.foreign_amount'])->toArray();
$foreignBalance = $this->sumTransactions($transactions, 'foreign_amount'); $foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');
$balance = bcadd($nativeBalance, $foreignBalance); return bcadd($nativeBalance, $foreignBalance);
$cache->store($balance);
return $balance;
} }
/** /**

View File

@@ -219,7 +219,7 @@ class TransactionGroupTwig extends AbstractExtension
/** @var Transaction $first */ /** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first(); $first = $journal->transactions()->where('amount', '<', 0)->first();
return null !== $first->foreign_amount; return '' !== $first->foreign_amount;
} }
/** /**
@@ -235,7 +235,7 @@ class TransactionGroupTwig extends AbstractExtension
/** @var Transaction $first */ /** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first(); $first = $journal->transactions()->where('amount', '<', 0)->first();
$currency = $first->foreignCurrency; $currency = $first->foreignCurrency;
$amount = $first->foreign_amount ?? '0'; $amount = '' === $first->foreign_amount ? '0' : $first->foreign_amount;
$colored = true; $colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type; $sourceType = $first->account()->first()->accountType()->first()->type;

View File

@@ -39,13 +39,12 @@ use Log;
*/ */
class UpdatePiggybank implements ActionInterface class UpdatePiggybank implements ActionInterface
{ {
/** @var RuleAction The rule action */ private RuleAction $action;
private $action;
/** /**
* TriggerInterface constructor. * TriggerInterface constructor.
* *
* @param RuleAction $action * @param RuleAction $action
*/ */
public function __construct(RuleAction $action) public function __construct(RuleAction $action)
{ {
@@ -60,10 +59,10 @@ class UpdatePiggybank implements ActionInterface
Log::debug(sprintf('Triggered rule action UpdatePiggybank on journal #%d', $journal['transaction_journal_id'])); Log::debug(sprintf('Triggered rule action UpdatePiggybank on journal #%d', $journal['transaction_journal_id']));
// refresh the transaction type. // refresh the transaction type.
$user = User::find($journal['user_id']); $user = User::find($journal['user_id']);
/** @var TransactionJournal $journalObj */ /** @var TransactionJournal $journalObj */
$journalObj = $user->transactionJournals()->find($journal['transaction_journal_id']); $journalObj = $user->transactionJournals()->find($journal['transaction_journal_id']);
$type = TransactionType::find((int) $journalObj->transaction_type_id); $type = TransactionType::find((int)$journalObj->transaction_type_id);
$journal['transaction_type_type'] = $type->type; $journal['transaction_type_type'] = $type->type;
if (TransactionType::TRANSFER !== $journal['transaction_type_type']) { if (TransactionType::TRANSFER !== $journal['transaction_type_type']) {
@@ -72,10 +71,10 @@ class UpdatePiggybank implements ActionInterface
return false; return false;
} }
$piggyBank = $this->findPiggybank($user); $piggyBank = $this->findPiggyBank($user);
if (null === $piggyBank) { if (null === $piggyBank) {
Log::info( Log::info(
sprintf('No piggy bank names "%s", cant execute action #%d of rule #%d', $this->action->action_value, $this->action->id, $this->action->rule_id) sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $this->action->action_value, $this->action->id, $this->action->rule_id)
); );
return false; return false;
@@ -84,20 +83,20 @@ class UpdatePiggybank implements ActionInterface
Log::debug(sprintf('Found piggy bank #%d ("%s")', $piggyBank->id, $piggyBank->name)); Log::debug(sprintf('Found piggy bank #%d ("%s")', $piggyBank->id, $piggyBank->name));
/** @var Transaction $source */ /** @var Transaction $source */
$source = Transaction::where('transaction_journal_id', $journal['transaction_journal_id'])->where('amount', '<', 0)->first();
/** @var Transaction $destination */ /** @var Transaction $destination */
$destination = Transaction::where('transaction_journal_id', $journal['transaction_journal_id'])->where('amount', '>', 0)->first(); $source = $journalObj->transactions()->where('amount', '<', 0)->first();
$destination = $journalObj->transactions()->where('amount', '>', 0)->first();
if ((int) $source->account_id === (int) $piggyBank->account_id) { if ((int)$source->account_id === (int)$piggyBank->account_id) {
Log::debug('Piggy bank account is linked to source, so remove amount.'); Log::debug('Piggy bank account is linked to source, so remove amount from piggy bank.');
$this->removeAmount($journal, $piggyBank, $destination->amount); $this->removeAmount($journal, $piggyBank, $destination->amount);
event(new TriggeredAuditLog($this->action->rule, $journalObj, 'remove_from_piggy', null, ['currency_symbol' => $journalObj->transactionCurrency->symbol, 'decimal_places' => $journalObj->transactionCurrency->decimal_places, 'amount' => $destination->amount, 'piggy' => $piggyBank->name])); event(new TriggeredAuditLog($this->action->rule, $journalObj, 'remove_from_piggy', null, ['currency_symbol' => $journalObj->transactionCurrency->symbol, 'decimal_places' => $journalObj->transactionCurrency->decimal_places, 'amount' => $destination->amount, 'piggy' => $piggyBank->name]));
return true; return true;
} }
if ((int) $destination->account_id === (int) $piggyBank->account_id) { if ((int)$destination->account_id === (int)$piggyBank->account_id) {
Log::debug('Piggy bank account is linked to source, so add amount.'); Log::debug('Piggy bank account is linked to source, so add amount to piggy bank.');
$this->addAmount($journal, $piggyBank, $destination->amount); $this->addAmount($journal, $piggyBank, $destination->amount);
event(new TriggeredAuditLog($this->action->rule, $journalObj, 'add_to_piggy', null, ['currency_symbol' => $journalObj->transactionCurrency->symbol, 'decimal_places' => $journalObj->transactionCurrency->decimal_places, 'amount' => $destination->amount, 'piggy' => $piggyBank->name])); event(new TriggeredAuditLog($this->action->rule, $journalObj, 'add_to_piggy', null, ['currency_symbol' => $journalObj->transactionCurrency->symbol, 'decimal_places' => $journalObj->transactionCurrency->decimal_places, 'amount' => $destination->amount, 'piggy' => $piggyBank->name]));
@@ -116,30 +115,30 @@ class UpdatePiggybank implements ActionInterface
} }
/** /**
* @param User $user * @param User $user
* *
* @return PiggyBank|null * @return PiggyBank|null
*/ */
private function findPiggybank(User $user): ?PiggyBank private function findPiggyBank(User $user): ?PiggyBank
{ {
return $user->piggyBanks()->where('piggy_banks.name', $this->action->action_value)->first(); return $user->piggyBanks()->where('piggy_banks.name', $this->action->action_value)->first();
} }
/** /**
* @param array $journalArray * @param PiggyBank $piggyBank
* @param PiggyBank $piggyBank * @param TransactionJournal $journal
* @param string $amount * @param string $amount
* @return void
*/ */
private function removeAmount(array $journalArray, PiggyBank $piggyBank, string $amount): void private function removeAmount(PiggyBank $piggyBank, TransactionJournal $journal, string $amount): void
{ {
$user = User::find($journalArray['user_id']);
$journal = $user->transactionJournals()->find($journalArray['transaction_journal_id']);
$repository = app(PiggyBankRepositoryInterface::class); $repository = app(PiggyBankRepositoryInterface::class);
$repository->setUser($journal->user); $repository->setUser($journal->user);
// how much can we remove from piggy bank? // how much can we remove from this piggy bank?
$toRemove = $repository->getCurrentAmount($piggyBank); $toRemove = $repository->getCurrentAmount($piggyBank);
Log::debug(sprintf('Amount is %s, max to remove is %s', $amount, $toRemove)); Log::debug(sprintf('Amount is %s, max to remove is %s', $amount, $toRemove));
// if $amount is bigger than $toRemove, shrink it. // if $amount is bigger than $toRemove, shrink it.
$amount = -1 === bccomp($amount, $toRemove) ? $amount : $toRemove; $amount = -1 === bccomp($amount, $toRemove) ? $amount : $toRemove;
Log::debug(sprintf('Amount is now %s', $amount)); Log::debug(sprintf('Amount is now %s', $amount));
@@ -159,19 +158,17 @@ class UpdatePiggybank implements ActionInterface
} }
Log::debug(sprintf('Will now remove %s from piggy bank.', $amount)); Log::debug(sprintf('Will now remove %s from piggy bank.', $amount));
$repository->removeAmount($piggyBank, $amount); $repository->removeAmount($piggyBank, $amount, $journal);
$repository->createEventWithJournal($piggyBank, app('steam')->negative($amount), $journal);
} }
/** /**
* @param array $journalArray * @param PiggyBank $piggyBank
* @param PiggyBank $piggyBank * @param TransactionJournal $journal
* @param string $amount * @param string $amount
* @return void
*/ */
private function addAmount(array $journalArray, PiggyBank $piggyBank, string $amount): void private function addAmount(PiggyBank $piggyBank, TransactionJournal $journal, string $amount): void
{ {
$user = User::find($journalArray['user_id']);
$journal = $user->transactionJournals()->find($journalArray['transaction_journal_id']);
$repository = app(PiggyBankRepositoryInterface::class); $repository = app(PiggyBankRepositoryInterface::class);
$repository->setUser($journal->user); $repository->setUser($journal->user);
@@ -198,7 +195,6 @@ class UpdatePiggybank implements ActionInterface
} }
Log::debug(sprintf('Will now add %s to piggy bank.', $amount)); Log::debug(sprintf('Will now add %s to piggy bank.', $amount));
$repository->addAmount($piggyBank, $amount); $repository->addAmount($piggyBank, $amount, $journal);
$repository->createEventWithJournal($piggyBank, app('steam')->positive($amount), $journal);
} }
} }

View File

@@ -92,7 +92,7 @@
"laravel/passport": "11.*", "laravel/passport": "11.*",
"laravel/sanctum": "^3.0", "laravel/sanctum": "^3.0",
"laravel/slack-notification-channel": "^2.4", "laravel/slack-notification-channel": "^2.4",
"laravel/ui": "^4.0", "laravel/ui": "^4.1",
"laravelcollective/html": "6.*", "laravelcollective/html": "6.*",
"league/commonmark": "2.*", "league/commonmark": "2.*",
"league/csv": "^9.7", "league/csv": "^9.7",
@@ -101,7 +101,7 @@
"pragmarx/google2fa": "^8.0", "pragmarx/google2fa": "^8.0",
"predis/predis": "^2.0", "predis/predis": "^2.0",
"psr/log": "<4", "psr/log": "<4",
"ramsey/uuid": "^4.5", "ramsey/uuid": "^4.6",
"rcrowe/twigbridge": "^0.14", "rcrowe/twigbridge": "^0.14",
"spatie/data-transfer-object": "^3.9", "spatie/data-transfer-object": "^3.9",
"spatie/laravel-ignition": "^1.5", "spatie/laravel-ignition": "^1.5",

715
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -231,5 +231,6 @@ return [
'attachment_notes_ends' => ['alias' => false, 'needs_context' => true], 'attachment_notes_ends' => ['alias' => false, 'needs_context' => true],
'attachment_notes_end' => ['alias' => true, 'alias_for' => 'attachment_notes_ends', 'needs_context' => true], 'attachment_notes_end' => ['alias' => true, 'alias_for' => 'attachment_notes_ends', 'needs_context' => true],
'exists' => ['alias' => false, 'needs_context' => false,], 'exists' => ['alias' => false, 'needs_context' => false,],
'sepa_ct_is' => ['alias' => false, 'needs_context' => true],
], ],
]; ];

View File

@@ -11,14 +11,14 @@
}, },
"dependencies": { "dependencies": {
"@popperjs/core": "^2.11.2", "@popperjs/core": "^2.11.2",
"@quasar/extras": "^1.15.4", "@quasar/extras": "^1.15.8",
"apexcharts": "^3.32.1", "apexcharts": "^3.32.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"axios-cache-adapter": "^2.7.3", "axios-cache-adapter": "^2.7.3",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"pinia": "^2.0.14", "pinia": "^2.0.14",
"quasar": "^2.8.4", "quasar": "^2.10.2",
"vue": "3", "vue": "3",
"vue-i18n": "^9.0.0", "vue-i18n": "^9.0.0",
"vue-router": "^4.0.0", "vue-router": "^4.0.0",
@@ -26,7 +26,7 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.13.14", "@babel/eslint-parser": "^7.13.14",
"@quasar/app-webpack": "^3.6.1", "@quasar/app-webpack": "^3.6.2",
"@types/node": "^12.20.21", "@types/node": "^12.20.21",
"@typescript-eslint/eslint-plugin": "^4.16.1", "@typescript-eslint/eslint-plugin": "^4.16.1",
"@typescript-eslint/parser": "^4.16.1", "@typescript-eslint/parser": "^4.16.1",

View File

@@ -1165,10 +1165,10 @@
resolved "https://registry.yarnpkg.com/@positron/stack-trace/-/stack-trace-1.0.0.tgz#14fcc712a530038ef9be1ce6952315a839f466a8" resolved "https://registry.yarnpkg.com/@positron/stack-trace/-/stack-trace-1.0.0.tgz#14fcc712a530038ef9be1ce6952315a839f466a8"
integrity sha1-FPzHEqUwA475vhzmlSMVqDn0Zqg= integrity sha1-FPzHEqUwA475vhzmlSMVqDn0Zqg=
"@quasar/app-webpack@^3.6.1": "@quasar/app-webpack@^3.6.2":
version "3.6.1" version "3.6.2"
resolved "https://registry.yarnpkg.com/@quasar/app-webpack/-/app-webpack-3.6.1.tgz#f2189316e931b77df9c3c63bf21f6108c3111a2a" resolved "https://registry.yarnpkg.com/@quasar/app-webpack/-/app-webpack-3.6.2.tgz#8ce387604687c36139a47f2d4efe394a20d8eb14"
integrity sha512-dwHs34fMXPaAY6iO4B0Qs6zexIS8kv9kI9LuYDEiU9uHndn6roH0Wsnk6MjiHk/4zPqFAKIVn6zF6FdE5nD9nA== integrity sha512-c1pVETEKUNYEJK0ZBRFgrIbXEttCByBhQYvVEFlmE2shbWJzIwqw2EqM/X4BXJ6xci6YyQyMmFVyHfGBxz/YwA==
dependencies: dependencies:
"@quasar/babel-preset-app" "2.0.1" "@quasar/babel-preset-app" "2.0.1"
"@quasar/fastclick" "1.1.5" "@quasar/fastclick" "1.1.5"
@@ -1261,10 +1261,10 @@
core-js "^3.6.5" core-js "^3.6.5"
core-js-compat "^3.6.5" core-js-compat "^3.6.5"
"@quasar/extras@^1.15.4": "@quasar/extras@^1.15.8":
version "1.15.4" version "1.15.8"
resolved "https://registry.yarnpkg.com/@quasar/extras/-/extras-1.15.4.tgz#c3c78416c2c39e4d4e791e8bd4dd6ff4b7e14b14" resolved "https://registry.yarnpkg.com/@quasar/extras/-/extras-1.15.8.tgz#948e35a7bc6006d97eb16273d1f05c99997fe126"
integrity sha512-GGURiH/K/IZM41RD9hcNG0Zly63sFGFZ97Q+doVMFSGBqNySfVNsb3WFSovOyL5K/Lfnb/sjzslroVIUoDVTKw== integrity sha512-UR6Snu7DSYdDOGqcNjUr0FJtKNfPn2Jc2hKTC+y/Y7Gf+vWu0RYUl49cguD33nn+wpbgs28+cvmjx7u3NNogoQ==
"@quasar/fastclick@1.1.5": "@quasar/fastclick@1.1.5":
version "1.1.5" version "1.1.5"
@@ -4193,9 +4193,9 @@ loader-runner@^4.2.0:
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
loader-utils@^1.0.2: loader-utils@^1.0.2:
version "1.4.0" version "1.4.2"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==
dependencies: dependencies:
big.js "^5.2.2" big.js "^5.2.2"
emojis-list "^3.0.0" emojis-list "^3.0.0"
@@ -4455,11 +4455,16 @@ minimatch@^5.0.1:
dependencies: dependencies:
brace-expansion "^2.0.1" brace-expansion "^2.0.1"
minimist@1.2.6, minimist@^1.2.0: minimist@1.2.6:
version "1.2.6" version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
minimist@^1.2.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
mrmime@^1.0.0: mrmime@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b"
@@ -5259,10 +5264,10 @@ qs@6.9.7:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
quasar@^2.8.4: quasar@^2.10.2:
version "2.8.4" version "2.10.2"
resolved "https://registry.yarnpkg.com/quasar/-/quasar-2.8.4.tgz#d32d7f0c1c4f313ee45f8f3d72028f3085727172" resolved "https://registry.yarnpkg.com/quasar/-/quasar-2.10.2.tgz#0a35d654a645d33fbe7dc537ea3be52917fa543d"
integrity sha512-bygg0GgSwQyrUJJTaHmYV50nVrz779QsNeH/cg2R/SHOQ4UmJI2FBA1hxU/nlpJ6DbmezNab1COa5ID57PvKfw== integrity sha512-y6suu0f2hJKrnFPHzx+p2EBVGzDF6xHaqYGkDIsMNkhxsrO9Qi2+dZCjq1J6+48EJiqPEOn8t9X/gT7yLSSnLw==
queue-microtask@^1.2.2: queue-microtask@^1.2.2:
version "1.2.3" version "1.2.3"

View File

@@ -14,8 +14,8 @@
}, },
"devDependencies": { "devDependencies": {
"@johmun/vue-tags-input": "^2", "@johmun/vue-tags-input": "^2",
"@vue/compiler-sfc": "^3.2.40", "@vue/compiler-sfc": "^3.2.45",
"axios": "^1.1", "axios": "^1.2",
"bootstrap-sass": "^3", "bootstrap-sass": "^3",
"cross-env": "^7.0", "cross-env": "^7.0",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",

View File

@@ -77,7 +77,7 @@ If you need support using Firefly III or the associated tools, come find us!
- [GitHub Discussions for questions and support](https://github.com/firefly-iii/firefly-iii/discussions/) - [GitHub Discussions for questions and support](https://github.com/firefly-iii/firefly-iii/discussions/)
- [Gitter.im for a good chat and a quick answer](https://gitter.im/firefly-iii/firefly-iii) - [Gitter.im for a good chat and a quick answer](https://gitter.im/firefly-iii/firefly-iii)
- [GitHub Issues for bugs and issues](https://github.com/firefly-iii/firefly-iii/issues) - [GitHub Issues for bugs and issues](https://github.com/firefly-iii/firefly-iii/issues)
- [Follow me around for news and updates on Twitter](https://twitter.com/Firefly_iii) - <a rel="me" href="https://fosstodon.org/@ff3">Follow me around for news and updates on Mastodon</a>
<!-- END OF HELP TEXT --> <!-- END OF HELP TEXT -->
@@ -138,7 +138,7 @@ There are many ways to run Firefly III
## Contributing ## Contributing
You can contact me at [james@firefly-iii.org](mailto:james@firefly-iii.org), you may open an issue in the [main repository](https://github.com/firefly-iii/firefly-iii) or contact me through [gitter](https://gitter.im/firefly-iii/firefly-iii) and [Twitter](https://twitter.com/Firefly_III). You can contact me at [james@firefly-iii.org](mailto:james@firefly-iii.org), you may open an issue in the [main repository](https://github.com/firefly-iii/firefly-iii) or contact me through [gitter](https://gitter.im/firefly-iii/firefly-iii) and [Mastodon](https://fosstodon.org/@ff3).
Of course, there are some [contributing guidelines](https://docs.firefly-iii.org/firefly-iii/other-pages/contributing) and a [code of conduct](https://github.com/firefly-iii/firefly-iii/blob/main/.github/code_of_conduct.md), which I invite you to check out. Of course, there are some [contributing guidelines](https://docs.firefly-iii.org/firefly-iii/other-pages/contributing) and a [code of conduct](https://github.com/firefly-iii/firefly-iii/blob/main/.github/code_of_conduct.md), which I invite you to check out.

View File

@@ -675,6 +675,7 @@ return [
'search_modifier_not_attachment_notes_contains' => 'Any attachment\'s notes do not contain ":value"', 'search_modifier_not_attachment_notes_contains' => 'Any attachment\'s notes do not contain ":value"',
'search_modifier_not_attachment_notes_starts' => 'Any attachment\'s notes start with ":value"', 'search_modifier_not_attachment_notes_starts' => 'Any attachment\'s notes start with ":value"',
'search_modifier_not_attachment_notes_ends' => 'Any attachment\'s notes do not end with ":value"', 'search_modifier_not_attachment_notes_ends' => 'Any attachment\'s notes do not end with ":value"',
'search_modifier_sepa_ct_is' => 'SEPA CT is ":value"',
'update_rule_from_query' => 'Update rule ":rule" from search query', 'update_rule_from_query' => 'Update rule ":rule" from search query',
'create_rule_from_query' => 'Create new rule from search query', 'create_rule_from_query' => 'Create new rule from search query',
'rule_from_search_words' => 'The rule engine has a hard time handling ":string". The suggested rule that fits your search query may give different results. Please verify the rule triggers carefully.', 'rule_from_search_words' => 'The rule engine has a hard time handling ":string". The suggested rule that fits your search query may give different results. Please verify the rule triggers carefully.',
@@ -898,6 +899,8 @@ return [
'rule_trigger_no_external_url_choice' => 'Transaction has no external URL', 'rule_trigger_no_external_url_choice' => 'Transaction has no external URL',
'rule_trigger_id_choice' => 'Transaction ID is..', 'rule_trigger_id_choice' => 'Transaction ID is..',
'rule_trigger_id' => 'Transaction ID is ":trigger_value"', 'rule_trigger_id' => 'Transaction ID is ":trigger_value"',
'rule_trigger_sepa_ct_is_choice' => 'SEPA CT is..',
'rule_trigger_sepa_ct_is' => 'SEPA CT is ":trigger_value"',
// new values: // new values:
'rule_trigger_user_action_choice' => 'User action is ":trigger_value"', 'rule_trigger_user_action_choice' => 'User action is ":trigger_value"',
@@ -2185,6 +2188,7 @@ return [
'no_tags' => '(no tags)', 'no_tags' => '(no tags)',
// piggy banks: // piggy banks:
'event_history' => 'Event history',
'add_money_to_piggy' => 'Add money to piggy bank ":name"', 'add_money_to_piggy' => 'Add money to piggy bank ":name"',
'piggy_bank' => 'Piggy bank', 'piggy_bank' => 'Piggy bank',
'new_piggy_bank' => 'New piggy bank', 'new_piggy_bank' => 'New piggy bank',

View File

@@ -98,7 +98,7 @@
</div> </div>
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">{{ 'transactions'|_ }}</h3> <h3 class="box-title">{{ 'event_history'|_ }}</h3>
</div> </div>
<div class="box-body no-padding" id="piggyEvents"> <div class="box-body no-padding" id="piggyEvents">
{% include 'list/piggy-bank-events' %} {% include 'list/piggy-bank-events' %}

120
yarn.lock
View File

@@ -1249,56 +1249,56 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@vue/compiler-core@3.2.41": "@vue/compiler-core@3.2.45":
version "3.2.41" version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.41.tgz#fb5b25f23817400f44377d878a0cdead808453ef" resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz#d9311207d96f6ebd5f4660be129fb99f01ddb41b"
integrity sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw== integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==
dependencies: dependencies:
"@babel/parser" "^7.16.4" "@babel/parser" "^7.16.4"
"@vue/shared" "3.2.41" "@vue/shared" "3.2.45"
estree-walker "^2.0.2" estree-walker "^2.0.2"
source-map "^0.6.1" source-map "^0.6.1"
"@vue/compiler-dom@3.2.41": "@vue/compiler-dom@3.2.45":
version "3.2.41" version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz#dc63dcd3ce8ca8a8721f14009d498a7a54380299" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce"
integrity sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw== integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==
dependencies: dependencies:
"@vue/compiler-core" "3.2.41" "@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.41" "@vue/shared" "3.2.45"
"@vue/compiler-sfc@2.7.13": "@vue/compiler-sfc@2.7.14":
version "2.7.13" version "2.7.14"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-2.7.13.tgz#818944f4a9616b752d48dac6a56bffe2db88bdff" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz#3446fd2fbb670d709277fc3ffa88efc5e10284fd"
integrity sha512-zzu2rLRZlgIU+OT3Atbr7Y6PG+LW4wVQpPfNRrGDH3dM9PsrcVfa+1pKb8bW467bGM3aDOvAnsYLWVpYIv3GRg== integrity sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==
dependencies: dependencies:
"@babel/parser" "^7.18.4" "@babel/parser" "^7.18.4"
postcss "^8.4.14" postcss "^8.4.14"
source-map "^0.6.1" source-map "^0.6.1"
"@vue/compiler-sfc@^3.2.40": "@vue/compiler-sfc@^3.2.45":
version "3.2.41" version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz#238fb8c48318408c856748f4116aff8cc1dc2a73" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70"
integrity sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w== integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==
dependencies: dependencies:
"@babel/parser" "^7.16.4" "@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.41" "@vue/compiler-core" "3.2.45"
"@vue/compiler-dom" "3.2.41" "@vue/compiler-dom" "3.2.45"
"@vue/compiler-ssr" "3.2.41" "@vue/compiler-ssr" "3.2.45"
"@vue/reactivity-transform" "3.2.41" "@vue/reactivity-transform" "3.2.45"
"@vue/shared" "3.2.41" "@vue/shared" "3.2.45"
estree-walker "^2.0.2" estree-walker "^2.0.2"
magic-string "^0.25.7" magic-string "^0.25.7"
postcss "^8.1.10" postcss "^8.1.10"
source-map "^0.6.1" source-map "^0.6.1"
"@vue/compiler-ssr@3.2.41": "@vue/compiler-ssr@3.2.45":
version "3.2.41" version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.41.tgz#344f564d68584b33367731c04ffc949784611fcb" resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2"
integrity sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ== integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==
dependencies: dependencies:
"@vue/compiler-dom" "3.2.41" "@vue/compiler-dom" "3.2.45"
"@vue/shared" "3.2.41" "@vue/shared" "3.2.45"
"@vue/component-compiler-utils@^3.1.0": "@vue/component-compiler-utils@^3.1.0":
version "3.3.0" version "3.3.0"
@@ -1316,21 +1316,21 @@
optionalDependencies: optionalDependencies:
prettier "^1.18.2 || ^2.0.0" prettier "^1.18.2 || ^2.0.0"
"@vue/reactivity-transform@3.2.41": "@vue/reactivity-transform@3.2.45":
version "3.2.41" version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz#9ff938877600c97f646e09ac1959b5150fb11a0c" resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz#07ac83b8138550c83dfb50db43cde1e0e5e8124d"
integrity sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A== integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==
dependencies: dependencies:
"@babel/parser" "^7.16.4" "@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.41" "@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.41" "@vue/shared" "3.2.45"
estree-walker "^2.0.2" estree-walker "^2.0.2"
magic-string "^0.25.7" magic-string "^0.25.7"
"@vue/shared@3.2.41": "@vue/shared@3.2.45":
version "3.2.41" version "3.2.45"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.41.tgz#fbc95422df654ea64e8428eced96ba6ad555d2bb" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2"
integrity sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw== integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
"@webassemblyjs/ast@1.11.1": "@webassemblyjs/ast@1.11.1":
version "1.11.1" version "1.11.1"
@@ -1619,10 +1619,10 @@ autoprefixer@^10.4.0:
picocolors "^1.0.0" picocolors "^1.0.0"
postcss-value-parser "^4.2.0" postcss-value-parser "^4.2.0"
axios@^1.1: axios@^1.2:
version "1.1.3" version "1.2.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35" resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.0.tgz#1cb65bd75162c70e9f8d118a905126c4a201d383"
integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA== integrity sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==
dependencies: dependencies:
follow-redirects "^1.15.0" follow-redirects "^1.15.0"
form-data "^4.0.0" form-data "^4.0.0"
@@ -3432,9 +3432,9 @@ loader-runner@^4.2.0:
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
loader-utils@^1.0.2, loader-utils@^1.1.0: loader-utils@^1.0.2, loader-utils@^1.1.0:
version "1.4.0" version "1.4.2"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==
dependencies: dependencies:
big.js "^5.2.2" big.js "^5.2.2"
emojis-list "^3.0.0" emojis-list "^3.0.0"
@@ -4247,9 +4247,9 @@ postcss@^7.0.36:
source-map "^0.6.1" source-map "^0.6.1"
postcss@^8.1.10, postcss@^8.2.15, postcss@^8.4, postcss@^8.4.14: postcss@^8.1.10, postcss@^8.2.15, postcss@^8.4, postcss@^8.4.14:
version "8.4.18" version "8.4.19"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.18.tgz#6d50046ea7d3d66a85e0e782074e7203bc7fbca2" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc"
integrity sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA== integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==
dependencies: dependencies:
nanoid "^3.3.4" nanoid "^3.3.4"
picocolors "^1.0.0" picocolors "^1.0.0"
@@ -5124,9 +5124,9 @@ vue-i18n@^8:
integrity sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA== integrity sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==
vue-loader@^15: vue-loader@^15:
version "15.10.0" version "15.10.1"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.10.0.tgz#2a12695c421a2a2cc2138f05a949d04ed086e38b" resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.10.1.tgz#c451c4cd05a911aae7b5dbbbc09fb913fb3cca18"
integrity sha512-VU6tuO8eKajrFeBzMssFUP9SvakEeeSi1BxdTH5o3+1yUyrldp8IERkSdXlMI2t4kxF2sqYUDsQY+WJBxzBmZg== integrity sha512-SaPHK1A01VrNthlix6h1hq4uJu7S/z0kdLUb6klubo738NeQoLbS6V9/d8Pv19tU0XdQKju3D1HSKuI8wJ5wMA==
dependencies: dependencies:
"@vue/component-compiler-utils" "^3.1.0" "@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2" hash-sum "^1.0.2"
@@ -5143,9 +5143,9 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.3:
loader-utils "^1.0.2" loader-utils "^1.0.2"
vue-template-compiler@^2.7: vue-template-compiler@^2.7:
version "2.7.13" version "2.7.14"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz#1520a5aa6d1af51dd0622824e79814f6e8cb7058" resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1"
integrity sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog== integrity sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==
dependencies: dependencies:
de-indent "^1.0.2" de-indent "^1.0.2"
he "^1.2.0" he "^1.2.0"
@@ -5156,11 +5156,11 @@ vue-template-es2015-compiler@^1.9.0:
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue@^2.6.10, vue@^2.7: vue@^2.6.10, vue@^2.7:
version "2.7.13" version "2.7.14"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.13.tgz#e9e499cc6da46dc7941c2510193b15aa6a84a79f" resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.14.tgz#3743dcd248fd3a34d421ae456b864a0246bafb17"
integrity sha512-QnM6ULTNnPmn71eUO+4hdjfBIA3H0GLsBnchnI/kS678tjI45GOUZhXd0oP/gX9isikXz1PAzSnkPspp9EUNfQ== integrity sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==
dependencies: dependencies:
"@vue/compiler-sfc" "2.7.13" "@vue/compiler-sfc" "2.7.14"
csstype "^3.1.0" csstype "^3.1.0"
watchpack@^2.4.0: watchpack@^2.4.0: