mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-25 06:51:08 +00:00
Implement custom trigger for recurring transactions
This commit is contained in:
@@ -57,7 +57,7 @@ class TransactionJournalMetaFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($data['data'] instanceof Carbon) {
|
if ($data['data'] instanceof Carbon) {
|
||||||
//Log::debug('Is a carbon object.');
|
Log::debug('Is a carbon object.');
|
||||||
$value = $data['data']->toW3cString();
|
$value = $data['data']->toW3cString();
|
||||||
}
|
}
|
||||||
if ('' === (string) $value) {
|
if ('' === (string) $value) {
|
||||||
|
@@ -166,7 +166,6 @@ class IndexController extends Controller
|
|||||||
|
|
||||||
$accounts->each(
|
$accounts->each(
|
||||||
function (Account $account) use ($activities, $startBalances, $endBalances) {
|
function (Account $account) use ($activities, $startBalances, $endBalances) {
|
||||||
|
|
||||||
$interest = (string)$this->repository->getMetaValue($account, 'interest');
|
$interest = (string)$this->repository->getMetaValue($account, 'interest');
|
||||||
$interest = '' === $interest ? '0' : $interest;
|
$interest = '' === $interest ? '0' : $interest;
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@ class ReconcileController extends Controller
|
|||||||
$startDate = clone $start;
|
$startDate = clone $start;
|
||||||
$startDate->subDay();
|
$startDate->subDay();
|
||||||
$startBalance = app('steam')->bcround(app('steam')->balance($account, $startDate), $currency->decimal_places);
|
$startBalance = app('steam')->bcround(app('steam')->balance($account, $startDate), $currency->decimal_places);
|
||||||
$endBalance = app('steam')->bcround( app('steam')->balance($account, $end), $currency->decimal_places);
|
$endBalance = app('steam')->bcround(app('steam')->balance($account, $end), $currency->decimal_places);
|
||||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
||||||
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
|
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
|
||||||
|
|
||||||
|
@@ -77,7 +77,7 @@ class AmountController extends Controller
|
|||||||
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, today(config('app.timezone')));
|
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, today(config('app.timezone')));
|
||||||
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
|
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
|
||||||
$maxAmount = $leftOnAccount;
|
$maxAmount = $leftOnAccount;
|
||||||
if (0 !== bccomp($piggyBank->targetamount,'0')) {
|
if (0 !== bccomp($piggyBank->targetamount, '0')) {
|
||||||
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
||||||
$maxAmount = min($leftOnAccount, $leftToSave);
|
$maxAmount = min($leftOnAccount, $leftToSave);
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ class AmountController extends Controller
|
|||||||
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
|
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
|
||||||
$maxAmount = $leftOnAccount;
|
$maxAmount = $leftOnAccount;
|
||||||
|
|
||||||
if (0 !== bccomp($piggyBank->targetamount,'0')) {
|
if (0 !== bccomp($piggyBank->targetamount, '0')) {
|
||||||
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
|
||||||
$maxAmount = min($leftOnAccount, $leftToSave);
|
$maxAmount = min($leftOnAccount, $leftToSave);
|
||||||
}
|
}
|
||||||
|
@@ -59,7 +59,7 @@ class ShowController extends Controller
|
|||||||
$this->middleware(
|
$this->middleware(
|
||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
app('view')->share('mainTitleIcon', 'fa-paint-brush');
|
app('view')->share('mainTitleIcon', 'fa-paint-brush');
|
||||||
app('view')->share('title', (string) trans('firefly.recurrences'));
|
app('view')->share('title', (string)trans('firefly.recurrences'));
|
||||||
|
|
||||||
$this->recurring = app(RecurringRepositoryInterface::class);
|
$this->recurring = app(RecurringRepositoryInterface::class);
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ class ShowController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Show a single recurring transaction.
|
* Show a single recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return Factory|View
|
* @return Factory|View
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -87,14 +87,19 @@ class ShowController extends Controller
|
|||||||
$today = today(config('app.timezone'));
|
$today = today(config('app.timezone'));
|
||||||
$array['repeat_until'] = null !== $array['repeat_until'] ? new Carbon($array['repeat_until']) : null;
|
$array['repeat_until'] = null !== $array['repeat_until'] ? new Carbon($array['repeat_until']) : null;
|
||||||
|
|
||||||
// transform dates back to Carbon objects:
|
// transform dates back to Carbon objects and expand information
|
||||||
foreach ($array['repetitions'] as $index => $repetition) {
|
foreach ($array['repetitions'] as $index => $repetition) {
|
||||||
foreach ($repetition['occurrences'] as $item => $occurrence) {
|
foreach ($repetition['occurrences'] as $item => $occurrence) {
|
||||||
$array['repetitions'][$index]['occurrences'][$item] = new Carbon($occurrence);
|
$date = (new Carbon($occurrence))->startOfDay();
|
||||||
|
$set = [
|
||||||
|
'date' => $date,
|
||||||
|
'fired' => $this->recurring->createdPreviously($recurrence, $date) || $this->recurring->getJournalCount($recurrence, $date) > 0,
|
||||||
|
];
|
||||||
|
$array['repetitions'][$index]['occurrences'][$item] = $set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$subTitle = (string) trans('firefly.overview_for_recurrence', ['title' => $recurrence->title]);
|
$subTitle = (string)trans('firefly.overview_for_recurrence', ['title' => $recurrence->title]);
|
||||||
|
|
||||||
return view('recurring.show', compact('recurrence', 'subTitle', 'array', 'groups', 'today'));
|
return view('recurring.show', compact('recurrence', 'subTitle', 'array', 'groups', 'today'));
|
||||||
}
|
}
|
||||||
|
89
app/Http/Controllers/Recurring/TriggerController.php
Normal file
89
app/Http/Controllers/Recurring/TriggerController.php
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* TriggerController.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\Http\Controllers\Recurring;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\Http\Requests\TriggerRecurrenceRequest;
|
||||||
|
use FireflyIII\Jobs\CreateRecurringTransactions;
|
||||||
|
use FireflyIII\Models\Recurrence;
|
||||||
|
use FireflyIII\Models\TransactionGroup;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TriggerController
|
||||||
|
*/
|
||||||
|
class TriggerController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Recurrence $recurrence
|
||||||
|
* @param TriggerRecurrenceRequest $request
|
||||||
|
* @return RedirectResponse
|
||||||
|
*/
|
||||||
|
public function trigger(Recurrence $recurrence, TriggerRecurrenceRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$all = $request->getAll();
|
||||||
|
$date = $all['date'];
|
||||||
|
|
||||||
|
// grab the date from the last time the recurrence fired:
|
||||||
|
$backupDate = $recurrence->latest_date;
|
||||||
|
|
||||||
|
// fire the recurring cron job on the given date, then post-date the created transaction.
|
||||||
|
Log::info(sprintf('Trigger: will now fire recurring cron job task for date "%s".', $date->format('Y-m-d H:i:s')));
|
||||||
|
/** @var CreateRecurringTransactions $job */
|
||||||
|
$job = app(CreateRecurringTransactions::class);
|
||||||
|
$job->setRecurrences(new Collection([$recurrence]));
|
||||||
|
$job->setDate($date);
|
||||||
|
$job->setForce(false);
|
||||||
|
$job->handle();
|
||||||
|
Log::debug('Done with recurrence.');
|
||||||
|
|
||||||
|
$groups = $job->getGroups();
|
||||||
|
/** @var TransactionGroup $group */
|
||||||
|
foreach ($groups as $group) {
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
foreach ($group->transactionJournals as $journal) {
|
||||||
|
Log::debug(sprintf('Set date of journal #%d to today!', $journal->id, $date));
|
||||||
|
$journal->date = Carbon::today();
|
||||||
|
$journal->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$recurrence->latest_date = $backupDate;
|
||||||
|
$recurrence->save();
|
||||||
|
app('preferences')->mark();
|
||||||
|
|
||||||
|
if (0 === $groups->count()) {
|
||||||
|
$request->session()->flash('info', (string)trans('firefly.no_new_transaction_in_recurrence'));
|
||||||
|
}
|
||||||
|
if (1 === $groups->count()) {
|
||||||
|
$first = $groups->first();
|
||||||
|
$request->session()->flash('success', (string)trans('firefly.stored_journal_no_descr'));
|
||||||
|
$request->session()->flash('success_url', route('transactions.show', [$first->id]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return redirect(route('recurring.show', [$recurrence->id]));
|
||||||
|
}
|
||||||
|
}
|
56
app/Http/Requests/TriggerRecurrenceRequest.php
Normal file
56
app/Http/Requests/TriggerRecurrenceRequest.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* TriggerRecurrenceRequest.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\Http\Requests;
|
||||||
|
|
||||||
|
use FireflyIII\Support\Request\ChecksLogin;
|
||||||
|
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class TriggerRecurrenceRequest extends FormRequest
|
||||||
|
{
|
||||||
|
use ConvertsDataTypes;
|
||||||
|
use ChecksLogin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data required by the controller.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAll(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'date' => $this->getCarbonDate('date'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rules for this request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'date' => 'required|date',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@@ -63,26 +63,27 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
private TransactionGroupRepositoryInterface $groupRepository;
|
private TransactionGroupRepositoryInterface $groupRepository;
|
||||||
private JournalRepositoryInterface $journalRepository;
|
private JournalRepositoryInterface $journalRepository;
|
||||||
private RecurringRepositoryInterface $repository;
|
private RecurringRepositoryInterface $repository;
|
||||||
|
private Collection $recurrences;
|
||||||
|
private Collection $groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
*
|
*
|
||||||
* @param Carbon|null $date
|
* @param Carbon|null $date
|
||||||
*/
|
*/
|
||||||
public function __construct(?Carbon $date)
|
public function __construct(?Carbon $date)
|
||||||
{
|
{
|
||||||
|
$newDate = new Carbon();
|
||||||
|
$newDate->startOfDay();
|
||||||
|
$this->date = $newDate;
|
||||||
|
|
||||||
if (null !== $date) {
|
if (null !== $date) {
|
||||||
$newDate = clone $date;
|
$newDate = clone $date;
|
||||||
$newDate->startOfDay();
|
$newDate->startOfDay();
|
||||||
$this->date = $newDate;
|
$this->date = $newDate;
|
||||||
}
|
}
|
||||||
if (null === $date) {
|
|
||||||
$newDate = new Carbon();
|
|
||||||
$newDate->startOfDay();
|
|
||||||
$this->date = $newDate;
|
|
||||||
}
|
|
||||||
$this->repository = app(RecurringRepositoryInterface::class);
|
$this->repository = app(RecurringRepositoryInterface::class);
|
||||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||||
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
||||||
@@ -90,6 +91,8 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
$this->submitted = 0;
|
$this->submitted = 0;
|
||||||
$this->executed = 0;
|
$this->executed = 0;
|
||||||
$this->created = 0;
|
$this->created = 0;
|
||||||
|
$this->recurrences = new Collection();
|
||||||
|
$this->groups = new Collection();
|
||||||
|
|
||||||
Log::debug(sprintf('Created new CreateRecurringTransactions("%s")', $this->date->format('Y-m-d')));
|
Log::debug(sprintf('Created new CreateRecurringTransactions("%s")', $this->date->format('Y-m-d')));
|
||||||
}
|
}
|
||||||
@@ -100,14 +103,23 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('Now at start of CreateRecurringTransactions() job for %s.', $this->date->format('D d M Y')));
|
Log::debug(sprintf('Now at start of CreateRecurringTransactions() job for %s.', $this->date->format('D d M Y')));
|
||||||
$recurrences = $this->repository->getAll();
|
|
||||||
|
// only use recurrences from database if there is no collection submitted.
|
||||||
|
if (0 !== count($this->recurrences)) {
|
||||||
|
Log::debug('Using predetermined set of recurrences.');
|
||||||
|
}
|
||||||
|
if (0 === count($this->recurrences)) {
|
||||||
|
Log::debug('Grab all recurrences from the database.');
|
||||||
|
$this->recurrences = $this->repository->getAll();
|
||||||
|
}
|
||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
$count = $recurrences->count();
|
$count = $this->recurrences->count();
|
||||||
$this->submitted = $count;
|
$this->submitted = $count;
|
||||||
Log::debug(sprintf('Count of collection is %d', $count));
|
Log::debug(sprintf('Count of collection is %d', $count));
|
||||||
|
|
||||||
// filter recurrences:
|
// filter recurrences:
|
||||||
$filtered = $this->filterRecurrences($recurrences);
|
$filtered = $this->filterRecurrences($this->recurrences);
|
||||||
Log::debug(sprintf('Left after filtering is %d', $filtered->count()));
|
Log::debug(sprintf('Left after filtering is %d', $filtered->count()));
|
||||||
/** @var Recurrence $recurrence */
|
/** @var Recurrence $recurrence */
|
||||||
foreach ($filtered as $recurrence) {
|
foreach ($filtered as $recurrence) {
|
||||||
@@ -141,7 +153,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $recurrences
|
* @param Collection $recurrences
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@@ -157,7 +169,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Is the info in the recurrence valid?
|
* Is the info in the recurrence valid?
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
@@ -179,6 +191,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// is no longer running
|
// is no longer running
|
||||||
if ($this->repeatUntilHasPassed($recurrence)) {
|
if ($this->repeatUntilHasPassed($recurrence)) {
|
||||||
Log::info(
|
Log::info(
|
||||||
@@ -221,7 +234,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Return recurring transaction is active.
|
* Return recurring transaction is active.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@@ -233,7 +246,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Return true if the $repeat_until date is in the past.
|
* Return true if the $repeat_until date is in the past.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@@ -246,7 +259,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Has the recurrence started yet?
|
* Has the recurrence started yet?
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@@ -261,7 +274,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Get the start date of a recurrence.
|
* Get the start date of a recurrence.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return Carbon
|
* @return Carbon
|
||||||
*/
|
*/
|
||||||
@@ -278,7 +291,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Has the recurrence fired today.
|
* Has the recurrence fired today.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@@ -291,7 +304,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
* Separate method that will loop all repetitions and do something with it. Will return
|
* Separate method that will loop all repetitions and do something with it. Will return
|
||||||
* all created transaction journals.
|
* all created transaction journals.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
* @throws DuplicateTransactionException
|
* @throws DuplicateTransactionException
|
||||||
@@ -312,7 +325,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
);
|
);
|
||||||
|
|
||||||
// start looping from $startDate to today perhaps we have a hit?
|
// start looping from $startDate to today perhaps we have a hit?
|
||||||
// add two days to $this->date so we always include the weekend.
|
// add two days to $this->date, so we always include the weekend.
|
||||||
$includeWeekend = clone $this->date;
|
$includeWeekend = clone $this->date;
|
||||||
$includeWeekend->addDays(2);
|
$includeWeekend->addDays(2);
|
||||||
$occurrences = $this->repository->getOccurrencesInRange($repetition, $recurrence->first_date, $includeWeekend);
|
$occurrences = $this->repository->getOccurrencesInRange($repetition, $recurrence->first_date, $includeWeekend);
|
||||||
@@ -329,9 +342,9 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Check if the occurences should be executed.
|
* Check if the occurences should be executed.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param array $occurrences
|
* @param array $occurrences
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
* @throws DuplicateTransactionException
|
* @throws DuplicateTransactionException
|
||||||
@@ -352,9 +365,9 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
*
|
*
|
||||||
* @return TransactionGroup|null
|
* @return TransactionGroup|null
|
||||||
* @throws DuplicateTransactionException
|
* @throws DuplicateTransactionException
|
||||||
@@ -376,13 +389,20 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->repository->createdPreviously($recurrence, $date) && false === $this->force) {
|
||||||
|
Log::info('There is a transaction already made for this date, so will not be created now');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($journalCount > 0 && true === $this->force) {
|
if ($journalCount > 0 && true === $this->force) {
|
||||||
app('log')->warning(sprintf('Already created %d groups for date %s but FORCED to continue.', $journalCount, $date->format('Y-m-d')));
|
app('log')->warning(sprintf('Already created %d groups for date %s but FORCED to continue.', $journalCount, $date->format('Y-m-d')));
|
||||||
}
|
}
|
||||||
|
|
||||||
// create transaction array and send to factory.
|
// create transaction array and send to factory.
|
||||||
$groupTitle = null;
|
$groupTitle = null;
|
||||||
$count = $recurrence->recurrenceTransactions->count();
|
$count = $recurrence->recurrenceTransactions->count();
|
||||||
if ($count > 1) {
|
if ($count > 1) {
|
||||||
/** @var RecurrenceTransaction $first */
|
/** @var RecurrenceTransaction $first */
|
||||||
|
|
||||||
@@ -408,6 +428,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
|
|
||||||
// trigger event:
|
// trigger event:
|
||||||
event(new StoredTransactionGroup($group, $recurrence->apply_rules, true));
|
event(new StoredTransactionGroup($group, $recurrence->apply_rules, true));
|
||||||
|
$this->groups->push($group);
|
||||||
|
|
||||||
// update recurring thing:
|
// update recurring thing:
|
||||||
$recurrence->latest_date = $date;
|
$recurrence->latest_date = $date;
|
||||||
@@ -419,9 +440,9 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Get transaction information from a recurring transaction.
|
* Get transaction information from a recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
@@ -439,7 +460,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
'type' => strtolower($recurrence->transactionType->type),
|
'type' => strtolower($recurrence->transactionType->type),
|
||||||
'date' => $date,
|
'date' => $date,
|
||||||
'user' => $recurrence->user_id,
|
'user' => $recurrence->user_id,
|
||||||
'currency_id' => (int) $transaction->transaction_currency_id,
|
'currency_id' => (int)$transaction->transaction_currency_id,
|
||||||
'currency_code' => null,
|
'currency_code' => null,
|
||||||
'description' => $transactions->first()->description,
|
'description' => $transactions->first()->description,
|
||||||
'amount' => $transaction->amount,
|
'amount' => $transaction->amount,
|
||||||
@@ -456,9 +477,9 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
'foreign_amount' => $transaction->foreign_amount,
|
'foreign_amount' => $transaction->foreign_amount,
|
||||||
'reconciled' => false,
|
'reconciled' => false,
|
||||||
'identifier' => $index,
|
'identifier' => $index,
|
||||||
'recurrence_id' => (int) $recurrence->id,
|
'recurrence_id' => (int)$recurrence->id,
|
||||||
'order' => $index,
|
'order' => $index,
|
||||||
'notes' => (string) trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]),
|
'notes' => (string)trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]),
|
||||||
'tags' => $this->repository->getTags($transaction),
|
'tags' => $this->repository->getTags($transaction),
|
||||||
'piggy_bank_id' => $this->repository->getPiggyBank($transaction),
|
'piggy_bank_id' => $this->repository->getPiggyBank($transaction),
|
||||||
'piggy_bank_name' => null,
|
'piggy_bank_name' => null,
|
||||||
@@ -466,6 +487,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
'bill_name' => null,
|
'bill_name' => null,
|
||||||
'recurrence_total' => $total,
|
'recurrence_total' => $total,
|
||||||
'recurrence_count' => $count,
|
'recurrence_count' => $count,
|
||||||
|
'recurrence_date' => $date,
|
||||||
];
|
];
|
||||||
$return[] = $single;
|
$return[] = $single;
|
||||||
}
|
}
|
||||||
@@ -474,7 +496,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
*/
|
*/
|
||||||
public function setDate(Carbon $date): void
|
public function setDate(Carbon $date): void
|
||||||
{
|
{
|
||||||
@@ -484,10 +506,26 @@ class CreateRecurringTransactions implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $force
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setForce(bool $force): void
|
public function setForce(bool $force): void
|
||||||
{
|
{
|
||||||
$this->force = $force;
|
$this->force = $force;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $recurrences
|
||||||
|
*/
|
||||||
|
public function setRecurrences(Collection $recurrences): void
|
||||||
|
{
|
||||||
|
$this->recurrences = $recurrences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getGroups(): Collection
|
||||||
|
{
|
||||||
|
return $this->groups;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,7 @@ use FireflyIII\Support\Repositories\Recurring\CalculateXOccurrences;
|
|||||||
use FireflyIII\Support\Repositories\Recurring\CalculateXOccurrencesSince;
|
use FireflyIII\Support\Repositories\Recurring\CalculateXOccurrencesSince;
|
||||||
use FireflyIII\Support\Repositories\Recurring\FiltersWeekends;
|
use FireflyIII\Support\Repositories\Recurring\FiltersWeekends;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use JsonException;
|
use JsonException;
|
||||||
@@ -63,7 +64,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Destroy a recurring transaction.
|
* Destroy a recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*/
|
*/
|
||||||
public function destroy(Recurrence $recurrence): void
|
public function destroy(Recurrence $recurrence): void
|
||||||
{
|
{
|
||||||
@@ -104,9 +105,9 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
{
|
{
|
||||||
// grab ALL recurring transactions:
|
// grab ALL recurring transactions:
|
||||||
return Recurrence::with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
|
return Recurrence::with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
|
||||||
->orderBy('active', 'DESC')
|
->orderBy('active', 'DESC')
|
||||||
->orderBy('title', 'ASC')
|
->orderBy('title', 'ASC')
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,7 +119,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/** @var RecurrenceTransactionMeta $meta */
|
/** @var RecurrenceTransactionMeta $meta */
|
||||||
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
||||||
if ('bill_id' === $meta->name) {
|
if ('bill_id' === $meta->name) {
|
||||||
$return = (int) $meta->value;
|
$return = (int)$meta->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the budget ID from a recurring transaction transaction.
|
* Get the budget ID from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|int
|
* @return null|int
|
||||||
*/
|
*/
|
||||||
@@ -138,7 +139,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/** @var RecurrenceTransactionMeta $meta */
|
/** @var RecurrenceTransactionMeta $meta */
|
||||||
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
||||||
if ('budget_id' === $meta->name) {
|
if ('budget_id' === $meta->name) {
|
||||||
$return = (int) $meta->value;
|
$return = (int)$meta->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the category from a recurring transaction transaction.
|
* Get the category from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|int
|
* @return null|int
|
||||||
*/
|
*/
|
||||||
@@ -158,7 +159,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/** @var RecurrenceTransactionMeta $meta */
|
/** @var RecurrenceTransactionMeta $meta */
|
||||||
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
||||||
if ('category_id' === $meta->name) {
|
if ('category_id' === $meta->name) {
|
||||||
$return = (int) $meta->value;
|
$return = (int)$meta->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the category from a recurring transaction transaction.
|
* Get the category from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
@@ -178,7 +179,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/** @var RecurrenceTransactionMeta $meta */
|
/** @var RecurrenceTransactionMeta $meta */
|
||||||
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
||||||
if ('category_name' === $meta->name) {
|
if ('category_name' === $meta->name) {
|
||||||
$return = (string) $meta->value;
|
$return = (string)$meta->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,33 +189,32 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Returns the journals created for this recurrence, possibly limited by time.
|
* Returns the journals created for this recurrence, possibly limited by time.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param Carbon|null $start
|
* @param Carbon|null $start
|
||||||
* @param Carbon|null $end
|
* @param Carbon|null $end
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getJournalCount(Recurrence $recurrence, Carbon $start = null, Carbon $end = null): int
|
public function getJournalCount(Recurrence $recurrence, Carbon $start = null, Carbon $end = null): int
|
||||||
{
|
{
|
||||||
$query = TransactionJournal::leftJoin('journal_meta', 'journal_meta.transaction_journal_id', '=', 'transaction_journals.id')
|
$query = TransactionJournal::leftJoin('journal_meta', 'journal_meta.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
->where('transaction_journals.user_id', $recurrence->user_id)
|
->where('transaction_journals.user_id', $recurrence->user_id)
|
||||||
->whereNull('transaction_journals.deleted_at')
|
->whereNull('transaction_journals.deleted_at')
|
||||||
->where('journal_meta.name', 'recurrence_id')
|
->where('journal_meta.name', 'recurrence_id')
|
||||||
->where('journal_meta.data', '"' . $recurrence->id . '"');
|
->where('journal_meta.data', '"'.$recurrence->id.'"');
|
||||||
if (null !== $start) {
|
if (null !== $start) {
|
||||||
$query->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'));
|
$query->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'));
|
||||||
}
|
}
|
||||||
if (null !== $end) {
|
if (null !== $end) {
|
||||||
$query->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'));
|
$query->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query->count(['transaction_journals.id']);
|
return $query->count(['transaction_journals.id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get journal ID's for journals created by this recurring transaction.
|
* Get journal ID's for journals created by this recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@@ -223,14 +223,14 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
return TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
return TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||||
->where('transaction_journals.user_id', $this->user->id)
|
->where('transaction_journals.user_id', $this->user->id)
|
||||||
->where('journal_meta.name', '=', 'recurrence_id')
|
->where('journal_meta.name', '=', 'recurrence_id')
|
||||||
->where('journal_meta.data', '=', json_encode((string) $recurrence->id))
|
->where('journal_meta.data', '=', json_encode((string)$recurrence->id))
|
||||||
->get(['journal_meta.transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
->get(['journal_meta.transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the notes.
|
* Get the notes.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@@ -239,14 +239,14 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/** @var Note $note */
|
/** @var Note $note */
|
||||||
$note = $recurrence->notes()->first();
|
$note = $recurrence->notes()->first();
|
||||||
if (null !== $note) {
|
if (null !== $note) {
|
||||||
return (string) $note->text;
|
return (string)$note->text;
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param RecurrenceTransaction $transaction
|
* @param RecurrenceTransaction $transaction
|
||||||
*
|
*
|
||||||
* @return int|null
|
* @return int|null
|
||||||
*/
|
*/
|
||||||
@@ -256,7 +256,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/** @var RecurrenceTransactionMeta $metaEntry */
|
/** @var RecurrenceTransactionMeta $metaEntry */
|
||||||
foreach ($meta as $metaEntry) {
|
foreach ($meta as $metaEntry) {
|
||||||
if ('piggy_bank_id' === $metaEntry->name) {
|
if ('piggy_bank_id' === $metaEntry->name) {
|
||||||
return (int) $metaEntry->value;
|
return (int)$metaEntry->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +266,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the tags from the recurring transaction.
|
* Get the tags from the recurring transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $transaction
|
* @param RecurrenceTransaction $transaction
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @throws JsonException
|
* @throws JsonException
|
||||||
@@ -285,23 +285,23 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param int $page
|
* @param int $page
|
||||||
* @param int $pageSize
|
* @param int $pageSize
|
||||||
*
|
*
|
||||||
* @return LengthAwarePaginator
|
* @return LengthAwarePaginator
|
||||||
*/
|
*/
|
||||||
public function getTransactionPaginator(Recurrence $recurrence, int $page, int $pageSize): LengthAwarePaginator
|
public function getTransactionPaginator(Recurrence $recurrence, int $page, int $pageSize): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
$journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
$journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||||
->whereNull('transaction_journals.deleted_at')
|
->whereNull('transaction_journals.deleted_at')
|
||||||
->where('transaction_journals.user_id', $this->user->id)
|
->where('transaction_journals.user_id', $this->user->id)
|
||||||
->where('name', 'recurrence_id')
|
->where('name', 'recurrence_id')
|
||||||
->where('data', json_encode((string) $recurrence->id))
|
->where('data', json_encode((string)$recurrence->id))
|
||||||
->get()->pluck('transaction_journal_id')->toArray();
|
->get()->pluck('transaction_journal_id')->toArray();
|
||||||
$search = [];
|
$search = [];
|
||||||
foreach ($journalMeta as $journalId) {
|
foreach ($journalMeta as $journalId) {
|
||||||
$search[] = (int) $journalId;
|
$search[] = (int)$journalId;
|
||||||
}
|
}
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
@@ -315,22 +315,22 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getTransactions(Recurrence $recurrence): Collection
|
public function getTransactions(Recurrence $recurrence): Collection
|
||||||
{
|
{
|
||||||
$journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
$journalMeta = TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||||
->whereNull('transaction_journals.deleted_at')
|
->whereNull('transaction_journals.deleted_at')
|
||||||
->where('transaction_journals.user_id', $this->user->id)
|
->where('transaction_journals.user_id', $this->user->id)
|
||||||
->where('name', 'recurrence_id')
|
->where('name', 'recurrence_id')
|
||||||
->where('data', json_encode((string) $recurrence->id))
|
->where('data', json_encode((string)$recurrence->id))
|
||||||
->get()->pluck('transaction_journal_id')->toArray();
|
->get()->pluck('transaction_journal_id')->toArray();
|
||||||
$search = [];
|
$search = [];
|
||||||
|
|
||||||
foreach ($journalMeta as $journalId) {
|
foreach ($journalMeta as $journalId) {
|
||||||
$search[] = (int) $journalId;
|
$search[] = (int)$journalId;
|
||||||
}
|
}
|
||||||
if (0 === count($search)) {
|
if (0 === count($search)) {
|
||||||
return new Collection();
|
return new Collection();
|
||||||
@@ -350,9 +350,9 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Calculate the next X iterations starting on the date given in $date.
|
* Calculate the next X iterations starting on the date given in $date.
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
* @param int $count
|
* @param int $count
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
@@ -387,10 +387,10 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
*
|
*
|
||||||
* Only returns them of they are after $afterDate
|
* Only returns them of they are after $afterDate
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
* @param Carbon $afterDate
|
* @param Carbon $afterDate
|
||||||
* @param int $count
|
* @param int $count
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@@ -425,8 +425,8 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon|null $max
|
* @param Carbon|null $max
|
||||||
* @param array $occurrences
|
* @param array $occurrences
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@@ -448,7 +448,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Parse the repetition in a string that is user readable.
|
* Parse the repetition in a string that is user readable.
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -460,26 +460,26 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
$pref = app('preferences')->getForUser($this->user, 'language', config('firefly.default_language', 'en_US'));
|
$pref = app('preferences')->getForUser($this->user, 'language', config('firefly.default_language', 'en_US'));
|
||||||
$language = $pref->data;
|
$language = $pref->data;
|
||||||
if ('daily' === $repetition->repetition_type) {
|
if ('daily' === $repetition->repetition_type) {
|
||||||
return (string) trans('firefly.recurring_daily', [], $language);
|
return (string)trans('firefly.recurring_daily', [], $language);
|
||||||
}
|
}
|
||||||
if ('weekly' === $repetition->repetition_type) {
|
if ('weekly' === $repetition->repetition_type) {
|
||||||
$dayOfWeek = trans(sprintf('config.dow_%s', $repetition->repetition_moment), [], $language);
|
$dayOfWeek = trans(sprintf('config.dow_%s', $repetition->repetition_moment), [], $language);
|
||||||
if ($repetition->repetition_skip > 0) {
|
if ($repetition->repetition_skip > 0) {
|
||||||
return (string) trans('firefly.recurring_weekly_skip', ['weekday' => $dayOfWeek, 'skip' => $repetition->repetition_skip + 1], $language);
|
return (string)trans('firefly.recurring_weekly_skip', ['weekday' => $dayOfWeek, 'skip' => $repetition->repetition_skip + 1], $language);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string) trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek], $language);
|
return (string)trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek], $language);
|
||||||
}
|
}
|
||||||
if ('monthly' === $repetition->repetition_type) {
|
if ('monthly' === $repetition->repetition_type) {
|
||||||
if ($repetition->repetition_skip > 0) {
|
if ($repetition->repetition_skip > 0) {
|
||||||
return (string) trans(
|
return (string)trans(
|
||||||
'firefly.recurring_monthly_skip',
|
'firefly.recurring_monthly_skip',
|
||||||
['dayOfMonth' => $repetition->repetition_moment, 'skip' => $repetition->repetition_skip + 1],
|
['dayOfMonth' => $repetition->repetition_moment, 'skip' => $repetition->repetition_skip + 1],
|
||||||
$language
|
$language
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string) trans(
|
return (string)trans(
|
||||||
'firefly.recurring_monthly',
|
'firefly.recurring_monthly',
|
||||||
['dayOfMonth' => $repetition->repetition_moment, 'skip' => $repetition->repetition_skip - 1],
|
['dayOfMonth' => $repetition->repetition_moment, 'skip' => $repetition->repetition_skip - 1],
|
||||||
$language
|
$language
|
||||||
@@ -490,7 +490,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
// first part is number of week, second is weekday.
|
// first part is number of week, second is weekday.
|
||||||
$dayOfWeek = trans(sprintf('config.dow_%s', $parts[1]), [], $language);
|
$dayOfWeek = trans(sprintf('config.dow_%s', $parts[1]), [], $language);
|
||||||
|
|
||||||
return (string) trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $parts[0]], $language);
|
return (string)trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $parts[0]], $language);
|
||||||
}
|
}
|
||||||
if ('yearly' === $repetition->repetition_type) {
|
if ('yearly' === $repetition->repetition_type) {
|
||||||
//
|
//
|
||||||
@@ -498,9 +498,9 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
$repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment);
|
$repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment);
|
||||||
$diffInYears = $today->diffInYears($repDate);
|
$diffInYears = $today->diffInYears($repDate);
|
||||||
$repDate->addYears($diffInYears); // technically not necessary.
|
$repDate->addYears($diffInYears); // technically not necessary.
|
||||||
$string = $repDate->isoFormat((string) trans('config.month_and_day_no_year_js'));
|
$string = $repDate->isoFormat((string)trans('config.month_and_day_no_year_js'));
|
||||||
|
|
||||||
return (string) trans('firefly.recurring_yearly', ['date' => $string], $language);
|
return (string)trans('firefly.recurring_yearly', ['date' => $string], $language);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
@@ -524,7 +524,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Set user for in repository.
|
* Set user for in repository.
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
*/
|
*/
|
||||||
public function setUser(User $user): void
|
public function setUser(User $user): void
|
||||||
{
|
{
|
||||||
@@ -532,7 +532,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
* @return Recurrence
|
* @return Recurrence
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -556,16 +556,16 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
public function totalTransactions(Recurrence $recurrence, RecurrenceRepetition $repetition): int
|
public function totalTransactions(Recurrence $recurrence, RecurrenceRepetition $repetition): int
|
||||||
{
|
{
|
||||||
// if repeat = null just return 0.
|
// if repeat = null just return 0.
|
||||||
if (null === $recurrence->repeat_until && 0 === (int) $recurrence->repetitions) {
|
if (null === $recurrence->repeat_until && 0 === (int)$recurrence->repetitions) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// expect X transactions then stop. Return that number
|
// expect X transactions then stop. Return that number
|
||||||
if (null === $recurrence->repeat_until && 0 !== (int) $recurrence->repetitions) {
|
if (null === $recurrence->repeat_until && 0 !== (int)$recurrence->repetitions) {
|
||||||
return (int) $recurrence->repetitions;
|
return (int)$recurrence->repetitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to calculate, this depends on the repetition:
|
// need to calculate, this depends on the repetition:
|
||||||
if (null !== $recurrence->repeat_until && 0 === (int) $recurrence->repetitions) {
|
if (null !== $recurrence->repeat_until && 0 === (int)$recurrence->repetitions) {
|
||||||
$occurrences = $this->getOccurrencesInRange($repetition, $recurrence->first_date ?? today(), $recurrence->repeat_until);
|
$occurrences = $this->getOccurrencesInRange($repetition, $recurrence->first_date ?? today(), $recurrence->repeat_until);
|
||||||
|
|
||||||
return count($occurrences);
|
return count($occurrences);
|
||||||
@@ -577,9 +577,9 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Generate events in the date range.
|
* Generate events in the date range.
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
@@ -616,8 +616,8 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Update a recurring transaction.
|
* Update a recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
* @return Recurrence
|
* @return Recurrence
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -629,4 +629,34 @@ class RecurringRepository implements RecurringRepositoryInterface
|
|||||||
|
|
||||||
return $service->update($recurrence, $data);
|
return $service->update($recurrence, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function createdPreviously(Recurrence $recurrence, Carbon $date): bool
|
||||||
|
{
|
||||||
|
// if not, loop set and try to read the recurrence_date. If it matches start or end, return it as well.
|
||||||
|
$set =
|
||||||
|
TransactionJournalMeta::where(function (Builder $q1) use ($recurrence) {
|
||||||
|
$q1->where('name', 'recurrence_id');
|
||||||
|
$q1->where('data', json_encode((string)$recurrence->id));
|
||||||
|
})->get(['journal_meta.transaction_journal_id']);
|
||||||
|
|
||||||
|
// there are X journals made for this recurrence. Any of them meant for today?
|
||||||
|
foreach ($set as $journalMeta) {
|
||||||
|
$count = TransactionJournalMeta::where(function (Builder $q2) use ($date) {
|
||||||
|
$string = (string)$date;
|
||||||
|
Log::debug(sprintf('Search for date: %s', json_encode($string)));
|
||||||
|
$q2->where('name', 'recurrence_date');
|
||||||
|
$q2->where('data', json_encode($string));
|
||||||
|
})
|
||||||
|
->where('transaction_journal_id', $journalMeta->transaction_journal_id)
|
||||||
|
->count();
|
||||||
|
if ($count > 0) {
|
||||||
|
Log::debug(sprintf('Looks like journal #%d was already created', $journalMeta->transaction_journal_id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,10 +41,17 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Destroy a recurring transaction.
|
* Destroy a recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*/
|
*/
|
||||||
public function destroy(Recurrence $recurrence): void;
|
public function destroy(Recurrence $recurrence): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Recurrence $recurrence
|
||||||
|
* @param Carbon $date
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function createdPreviously(Recurrence $recurrence, Carbon $date): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy all recurring transactions.
|
* Destroy all recurring transactions.
|
||||||
*/
|
*/
|
||||||
@@ -67,7 +74,7 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the category from a recurring transaction transaction.
|
* Get the category from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|int
|
* @return null|int
|
||||||
*/
|
*/
|
||||||
@@ -76,7 +83,7 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the budget ID from a recurring transaction transaction.
|
* Get the budget ID from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|int
|
* @return null|int
|
||||||
*/
|
*/
|
||||||
@@ -85,7 +92,7 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the category from a recurring transaction transaction.
|
* Get the category from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|int
|
* @return null|int
|
||||||
*/
|
*/
|
||||||
@@ -94,7 +101,7 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the category from a recurring transaction transaction.
|
* Get the category from a recurring transaction transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $recTransaction
|
* @param RecurrenceTransaction $recTransaction
|
||||||
*
|
*
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
@@ -103,9 +110,9 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Returns the count of journals created for this recurrence, possibly limited by time.
|
* Returns the count of journals created for this recurrence, possibly limited by time.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param Carbon|null $start
|
* @param Carbon|null $start
|
||||||
* @param Carbon|null $end
|
* @param Carbon|null $end
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@@ -114,7 +121,7 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get journal ID's for journals created by this recurring transaction.
|
* Get journal ID's for journals created by this recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@@ -123,7 +130,7 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the notes.
|
* Get the notes.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@@ -132,16 +139,16 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Generate events in the date range.
|
* Generate events in the date range.
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array;
|
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param RecurrenceTransaction $transaction
|
* @param RecurrenceTransaction $transaction
|
||||||
*
|
*
|
||||||
* @return int|null
|
* @return int|null
|
||||||
*/
|
*/
|
||||||
@@ -150,23 +157,23 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Get the tags from the recurring transaction.
|
* Get the tags from the recurring transaction.
|
||||||
*
|
*
|
||||||
* @param RecurrenceTransaction $transaction
|
* @param RecurrenceTransaction $transaction
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getTags(RecurrenceTransaction $transaction): array;
|
public function getTags(RecurrenceTransaction $transaction): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param int $page
|
* @param int $page
|
||||||
* @param int $pageSize
|
* @param int $pageSize
|
||||||
*
|
*
|
||||||
* @return LengthAwarePaginator
|
* @return LengthAwarePaginator
|
||||||
*/
|
*/
|
||||||
public function getTransactionPaginator(Recurrence $recurrence, int $page, int $pageSize): LengthAwarePaginator;
|
public function getTransactionPaginator(Recurrence $recurrence, int $page, int $pageSize): LengthAwarePaginator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@@ -176,9 +183,9 @@ interface RecurringRepositoryInterface
|
|||||||
* Calculate the next X iterations starting on the date given in $date.
|
* Calculate the next X iterations starting on the date given in $date.
|
||||||
* Returns an array of Carbon objects.
|
* Returns an array of Carbon objects.
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
* @param int $count
|
* @param int $count
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -191,10 +198,10 @@ interface RecurringRepositoryInterface
|
|||||||
*
|
*
|
||||||
* Only returns them of they are after $afterDate
|
* Only returns them of they are after $afterDate
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
* @param Carbon $afterDate
|
* @param Carbon $afterDate
|
||||||
* @param int $count
|
* @param int $count
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -204,15 +211,15 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Parse the repetition in a string that is user readable.
|
* Parse the repetition in a string that is user readable.
|
||||||
*
|
*
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function repetitionDescription(RecurrenceRepetition $repetition): string;
|
public function repetitionDescription(RecurrenceRepetition $repetition): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $query
|
* @param string $query
|
||||||
* @param int $limit
|
* @param int $limit
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@@ -221,14 +228,14 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Set user for in repository.
|
* Set user for in repository.
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
*/
|
*/
|
||||||
public function setUser(User $user): void;
|
public function setUser(User $user): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a new recurring transaction.
|
* Store a new recurring transaction.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
* @return Recurrence
|
* @return Recurrence
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
@@ -238,8 +245,8 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Calculate how many transactions are to be expected from this recurrence.
|
* Calculate how many transactions are to be expected from this recurrence.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param RecurrenceRepetition $repetition
|
* @param RecurrenceRepetition $repetition
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@@ -248,8 +255,8 @@ interface RecurringRepositoryInterface
|
|||||||
/**
|
/**
|
||||||
* Update a recurring transaction.
|
* Update a recurring transaction.
|
||||||
*
|
*
|
||||||
* @param Recurrence $recurrence
|
* @param Recurrence $recurrence
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
* @return Recurrence
|
* @return Recurrence
|
||||||
*/
|
*/
|
||||||
|
@@ -485,7 +485,7 @@ trait AccountServiceTrait
|
|||||||
$sourceName = trans('firefly.liability_credit_description', ['account' => $account->name], $language);
|
$sourceName = trans('firefly.liability_credit_description', ['account' => $account->name], $language);
|
||||||
$destId = $account->id;
|
$destId = $account->id;
|
||||||
$destName = null;
|
$destName = null;
|
||||||
if(-1 === bccomp($openingBalance, '0')) {
|
if (-1 === bccomp($openingBalance, '0')) {
|
||||||
// amount is negative, reverse it
|
// amount is negative, reverse it
|
||||||
$sourceId = $account->id;
|
$sourceId = $account->id;
|
||||||
$sourceName = null;
|
$sourceName = null;
|
||||||
|
@@ -104,16 +104,15 @@ class Steam
|
|||||||
*/
|
*/
|
||||||
public function bcround(?string $number, int $precision = 0): string
|
public function bcround(?string $number, int $precision = 0): string
|
||||||
{
|
{
|
||||||
|
if (null === $number) {
|
||||||
if(null === $number) {
|
|
||||||
return '0';
|
return '0';
|
||||||
}
|
}
|
||||||
if('' === trim($number)) {
|
if ('' === trim($number)) {
|
||||||
return '0';
|
return '0';
|
||||||
}
|
}
|
||||||
// if the number contains "E", it's in scientific notation, so we need to convert it to a normal number first.
|
// if the number contains "E", it's in scientific notation, so we need to convert it to a normal number first.
|
||||||
if(false !== stripos($number,'e')) {
|
if (false !== stripos($number, 'e')) {
|
||||||
$number = sprintf('%.24f',$number);
|
$number = sprintf('%.24f', $number);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
|
Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
|
||||||
|
@@ -156,7 +156,7 @@ return [
|
|||||||
'languages' => [
|
'languages' => [
|
||||||
// currently enabled languages
|
// currently enabled languages
|
||||||
'bg_BG' => ['name_locale' => 'Български', 'name_english' => 'Bulgarian'],
|
'bg_BG' => ['name_locale' => 'Български', 'name_english' => 'Bulgarian'],
|
||||||
// 'ca_ES' => ['name_locale' => 'Catalan', 'name_english' => 'Catalan'],
|
// 'ca_ES' => ['name_locale' => 'Catalan', 'name_english' => 'Catalan'],
|
||||||
'cs_CZ' => ['name_locale' => 'Czech', 'name_english' => 'Czech'],
|
'cs_CZ' => ['name_locale' => 'Czech', 'name_english' => 'Czech'],
|
||||||
'da_DK' => ['name_locale' => 'Danish', 'name_english' => 'Danish'],
|
'da_DK' => ['name_locale' => 'Danish', 'name_english' => 'Danish'],
|
||||||
'de_DE' => ['name_locale' => 'Deutsch', 'name_english' => 'German'],
|
'de_DE' => ['name_locale' => 'Deutsch', 'name_english' => 'German'],
|
||||||
@@ -164,17 +164,17 @@ return [
|
|||||||
'en_GB' => ['name_locale' => 'English (GB)', 'name_english' => 'English (GB)'],
|
'en_GB' => ['name_locale' => 'English (GB)', 'name_english' => 'English (GB)'],
|
||||||
'en_US' => ['name_locale' => 'English (US)', 'name_english' => 'English (US)'],
|
'en_US' => ['name_locale' => 'English (US)', 'name_english' => 'English (US)'],
|
||||||
'es_ES' => ['name_locale' => 'Español', 'name_english' => 'Spanish'],
|
'es_ES' => ['name_locale' => 'Español', 'name_english' => 'Spanish'],
|
||||||
// 'et_EE' => ['name_locale' => 'Estonian', 'name_english' => 'Estonian'],
|
// 'et_EE' => ['name_locale' => 'Estonian', 'name_english' => 'Estonian'],
|
||||||
// 'fa_IR' => ['name_locale' => 'فارسی', 'name_english' => 'Persian'],
|
// 'fa_IR' => ['name_locale' => 'فارسی', 'name_english' => 'Persian'],
|
||||||
'fi_FI' => ['name_locale' => 'Suomi', 'name_english' => 'Finnish'],
|
'fi_FI' => ['name_locale' => 'Suomi', 'name_english' => 'Finnish'],
|
||||||
'fr_FR' => ['name_locale' => 'Français', 'name_english' => 'French'],
|
'fr_FR' => ['name_locale' => 'Français', 'name_english' => 'French'],
|
||||||
// 'he_IL' => ['name_locale' => 'Hebrew', 'name_english' => 'Hebrew'],
|
// 'he_IL' => ['name_locale' => 'Hebrew', 'name_english' => 'Hebrew'],
|
||||||
'hu_HU' => ['name_locale' => 'Hungarian', 'name_english' => 'Hungarian'],
|
'hu_HU' => ['name_locale' => 'Hungarian', 'name_english' => 'Hungarian'],
|
||||||
'id_ID' => ['name_locale' => 'Bahasa Indonesia', 'name_english' => 'Indonesian'],
|
'id_ID' => ['name_locale' => 'Bahasa Indonesia', 'name_english' => 'Indonesian'],
|
||||||
// 'is_IS' => ['name_locale' => 'Icelandic', 'name_english' => 'Icelandic'],
|
// 'is_IS' => ['name_locale' => 'Icelandic', 'name_english' => 'Icelandic'],
|
||||||
'it_IT' => ['name_locale' => 'Italiano', 'name_english' => 'Italian'],
|
'it_IT' => ['name_locale' => 'Italiano', 'name_english' => 'Italian'],
|
||||||
'ja_JP' => ['name_locale' => 'Japanese', 'name_english' => 'Japanese'],
|
'ja_JP' => ['name_locale' => 'Japanese', 'name_english' => 'Japanese'],
|
||||||
// 'lt_LT' => ['name_locale' => 'Lietuvių', 'name_english' => 'Lithuanian'],
|
// 'lt_LT' => ['name_locale' => 'Lietuvių', 'name_english' => 'Lithuanian'],
|
||||||
'nb_NO' => ['name_locale' => 'Norsk', 'name_english' => 'Norwegian'],
|
'nb_NO' => ['name_locale' => 'Norsk', 'name_english' => 'Norwegian'],
|
||||||
'nl_NL' => ['name_locale' => 'Nederlands', 'name_english' => 'Dutch'],
|
'nl_NL' => ['name_locale' => 'Nederlands', 'name_english' => 'Dutch'],
|
||||||
'pl_PL' => ['name_locale' => 'Polski', 'name_english' => 'Polish'],
|
'pl_PL' => ['name_locale' => 'Polski', 'name_english' => 'Polish'],
|
||||||
@@ -182,12 +182,12 @@ return [
|
|||||||
'pt_PT' => ['name_locale' => 'Português', 'name_english' => 'Portuguese'],
|
'pt_PT' => ['name_locale' => 'Português', 'name_english' => 'Portuguese'],
|
||||||
'ro_RO' => ['name_locale' => 'Română', 'name_english' => 'Romanian'],
|
'ro_RO' => ['name_locale' => 'Română', 'name_english' => 'Romanian'],
|
||||||
'ru_RU' => ['name_locale' => 'Русский', 'name_english' => 'Russian'],
|
'ru_RU' => ['name_locale' => 'Русский', 'name_english' => 'Russian'],
|
||||||
// 'si_LK' => ['name_locale' => 'සිංහල', 'name_english' => 'Sinhala (Sri Lanka)'],
|
// 'si_LK' => ['name_locale' => 'සිංහල', 'name_english' => 'Sinhala (Sri Lanka)'],
|
||||||
'sk_SK' => ['name_locale' => 'Slovenčina', 'name_english' => 'Slovak'],
|
'sk_SK' => ['name_locale' => 'Slovenčina', 'name_english' => 'Slovak'],
|
||||||
'sl_SI' => ['name_locale' => 'Slovenian', 'name_english' => 'Slovenian'],
|
'sl_SI' => ['name_locale' => 'Slovenian', 'name_english' => 'Slovenian'],
|
||||||
//// 'sr_CS' => ['name_locale' => 'Serbian (Latin)', 'name_english' => 'Serbian (Latin)'],
|
//// 'sr_CS' => ['name_locale' => 'Serbian (Latin)', 'name_english' => 'Serbian (Latin)'],
|
||||||
'sv_SE' => ['name_locale' => 'Svenska', 'name_english' => 'Swedish'],
|
'sv_SE' => ['name_locale' => 'Svenska', 'name_english' => 'Swedish'],
|
||||||
// // 'tlh_AA' => ['name_locale' => 'tlhIngan Hol', 'name_english' => 'Klingon'],
|
// // 'tlh_AA' => ['name_locale' => 'tlhIngan Hol', 'name_english' => 'Klingon'],
|
||||||
'tr_TR' => ['name_locale' => 'Türkçe', 'name_english' => 'Turkish'],
|
'tr_TR' => ['name_locale' => 'Türkçe', 'name_english' => 'Turkish'],
|
||||||
'uk_UA' => ['name_locale' => 'Ukranian', 'name_english' => 'Ukranian'],
|
'uk_UA' => ['name_locale' => 'Ukranian', 'name_english' => 'Ukranian'],
|
||||||
'vi_VN' => ['name_locale' => 'Tiếng Việt', 'name_english' => 'Vietnamese'],
|
'vi_VN' => ['name_locale' => 'Tiếng Việt', 'name_english' => 'Vietnamese'],
|
||||||
@@ -221,9 +221,14 @@ return [
|
|||||||
|
|
||||||
// account types that may have or set a currency
|
// account types that may have or set a currency
|
||||||
'valid_currency_account_types' => [
|
'valid_currency_account_types' => [
|
||||||
AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE,
|
AccountType::ASSET,
|
||||||
AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT,
|
AccountType::LOAN,
|
||||||
AccountType::RECONCILIATION
|
AccountType::DEBT,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::CASH,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LIABILITY_CREDIT,
|
||||||
|
AccountType::RECONCILIATION,
|
||||||
],
|
],
|
||||||
|
|
||||||
// "value must be in this list" values
|
// "value must be in this list" values
|
||||||
@@ -528,8 +533,13 @@ return [
|
|||||||
TransactionTypeModel::WITHDRAWAL => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeModel::WITHDRAWAL => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
TransactionTypeEnum::DEPOSIT->value => [AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeEnum::DEPOSIT->value => [AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
|
TransactionTypeModel::OPENING_BALANCE => [
|
||||||
AccountType::MORTGAGE,],
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::ASSET,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
],
|
||||||
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
|
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
|
||||||
TransactionTypeModel::LIABILITY_CREDIT => [AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeModel::LIABILITY_CREDIT => [AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
// in case no transaction type is known yet, it could be anything.
|
// in case no transaction type is known yet, it could be anything.
|
||||||
@@ -543,46 +553,111 @@ return [
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
'destination' => [
|
'destination' => [
|
||||||
TransactionTypeModel::WITHDRAWAL => [AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT,
|
TransactionTypeModel::WITHDRAWAL => [
|
||||||
AccountType::MORTGAGE,],
|
AccountType::EXPENSE,
|
||||||
|
AccountType::CASH,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
],
|
||||||
TransactionTypeEnum::DEPOSIT->value => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeEnum::DEPOSIT->value => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeModel::TRANSFER => [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
TransactionTypeModel::OPENING_BALANCE => [AccountType::INITIAL_BALANCE, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT,
|
TransactionTypeModel::OPENING_BALANCE => [
|
||||||
AccountType::MORTGAGE,],
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::ASSET,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
],
|
||||||
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
|
TransactionTypeModel::RECONCILIATION => [AccountType::RECONCILIATION, AccountType::ASSET],
|
||||||
TransactionTypeModel::LIABILITY_CREDIT => [AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
TransactionTypeModel::LIABILITY_CREDIT => [AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'allowed_opposing_types' => [
|
'allowed_opposing_types' => [
|
||||||
'source' => [
|
'source' => [
|
||||||
AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE,
|
AccountType::ASSET => [
|
||||||
AccountType::LOAN, AccountType::RECONCILIATION, AccountType::MORTGAGE],
|
AccountType::ASSET,
|
||||||
|
AccountType::CASH,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::EXPENSE,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::RECONCILIATION,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
],
|
||||||
AccountType::CASH => [AccountType::ASSET],
|
AccountType::CASH => [AccountType::ASSET],
|
||||||
AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
|
AccountType::DEBT => [
|
||||||
AccountType::MORTGAGE, AccountType::LIABILITY_CREDIT],
|
AccountType::ASSET,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::EXPENSE,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::LIABILITY_CREDIT,
|
||||||
|
],
|
||||||
AccountType::EXPENSE => [], // is not allowed as a source.
|
AccountType::EXPENSE => [], // is not allowed as a source.
|
||||||
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
||||||
AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
|
AccountType::LOAN => [
|
||||||
AccountType::MORTGAGE, AccountType::LIABILITY_CREDIT],
|
AccountType::ASSET,
|
||||||
AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::EXPENSE, AccountType::INITIAL_BALANCE, AccountType::LOAN,
|
AccountType::DEBT,
|
||||||
AccountType::MORTGAGE, AccountType::LIABILITY_CREDIT],
|
AccountType::EXPENSE,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::LIABILITY_CREDIT,
|
||||||
|
],
|
||||||
|
AccountType::MORTGAGE => [
|
||||||
|
AccountType::ASSET,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::EXPENSE,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::LIABILITY_CREDIT,
|
||||||
|
],
|
||||||
AccountType::RECONCILIATION => [AccountType::ASSET],
|
AccountType::RECONCILIATION => [AccountType::ASSET],
|
||||||
AccountType::REVENUE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
AccountType::REVENUE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
||||||
AccountType::LIABILITY_CREDIT => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
AccountType::LIABILITY_CREDIT => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
||||||
|
|
||||||
],
|
],
|
||||||
'destination' => [
|
'destination' => [
|
||||||
AccountType::ASSET => [AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN,
|
AccountType::ASSET => [
|
||||||
AccountType::MORTGAGE, AccountType::RECONCILIATION, AccountType::REVENUE,],
|
AccountType::ASSET,
|
||||||
|
AccountType::CASH,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::RECONCILIATION,
|
||||||
|
AccountType::REVENUE,
|
||||||
|
],
|
||||||
AccountType::CASH => [AccountType::ASSET],
|
AccountType::CASH => [AccountType::ASSET],
|
||||||
AccountType::DEBT => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
|
AccountType::DEBT => [
|
||||||
AccountType::REVENUE,],
|
AccountType::ASSET,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::REVENUE,
|
||||||
|
],
|
||||||
AccountType::EXPENSE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
AccountType::EXPENSE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
||||||
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
AccountType::INITIAL_BALANCE => [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE],
|
||||||
AccountType::LOAN => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
|
AccountType::LOAN => [
|
||||||
AccountType::REVENUE,],
|
AccountType::ASSET,
|
||||||
AccountType::MORTGAGE => [AccountType::ASSET, AccountType::DEBT, AccountType::INITIAL_BALANCE, AccountType::LOAN, AccountType::MORTGAGE,
|
AccountType::DEBT,
|
||||||
AccountType::REVENUE,],
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::REVENUE,
|
||||||
|
],
|
||||||
|
AccountType::MORTGAGE => [
|
||||||
|
AccountType::ASSET,
|
||||||
|
AccountType::DEBT,
|
||||||
|
AccountType::INITIAL_BALANCE,
|
||||||
|
AccountType::LOAN,
|
||||||
|
AccountType::MORTGAGE,
|
||||||
|
AccountType::REVENUE,
|
||||||
|
],
|
||||||
AccountType::RECONCILIATION => [AccountType::ASSET],
|
AccountType::RECONCILIATION => [AccountType::ASSET],
|
||||||
AccountType::REVENUE => [], // is not allowed as a destination
|
AccountType::REVENUE => [], // is not allowed as a destination
|
||||||
AccountType::LIABILITY_CREDIT => [],// is not allowed as a destination
|
AccountType::LIABILITY_CREDIT => [],// is not allowed as a destination
|
||||||
@@ -591,31 +666,66 @@ return [
|
|||||||
// depending on the account type, return the allowed transaction types:
|
// depending on the account type, return the allowed transaction types:
|
||||||
'allowed_transaction_types' => [
|
'allowed_transaction_types' => [
|
||||||
'source' => [
|
'source' => [
|
||||||
AccountType::ASSET => [TransactionTypeModel::WITHDRAWAL, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE,
|
AccountType::ASSET => [
|
||||||
TransactionTypeModel::RECONCILIATION,],
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
|
TransactionTypeModel::TRANSFER,
|
||||||
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
|
TransactionTypeModel::RECONCILIATION,
|
||||||
|
],
|
||||||
AccountType::EXPENSE => [], // is not allowed as a source.
|
AccountType::EXPENSE => [], // is not allowed as a source.
|
||||||
AccountType::REVENUE => [TransactionTypeEnum::DEPOSIT->value],
|
AccountType::REVENUE => [TransactionTypeEnum::DEPOSIT->value],
|
||||||
AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER,
|
AccountType::LOAN => [
|
||||||
TransactionTypeModel::OPENING_BALANCE, TransactionTypeModel::LIABILITY_CREDIT],
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER,
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
TransactionTypeModel::OPENING_BALANCE, TransactionTypeModel::LIABILITY_CREDIT],
|
TransactionTypeModel::TRANSFER,
|
||||||
AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER,
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
TransactionTypeModel::OPENING_BALANCE, TransactionTypeModel::LIABILITY_CREDIT],
|
TransactionTypeModel::LIABILITY_CREDIT,
|
||||||
|
],
|
||||||
|
AccountType::DEBT => [
|
||||||
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
|
TransactionTypeModel::TRANSFER,
|
||||||
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
|
TransactionTypeModel::LIABILITY_CREDIT,
|
||||||
|
],
|
||||||
|
AccountType::MORTGAGE => [
|
||||||
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
|
TransactionTypeModel::TRANSFER,
|
||||||
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
|
TransactionTypeModel::LIABILITY_CREDIT,
|
||||||
|
],
|
||||||
AccountType::INITIAL_BALANCE => [TransactionTypeModel::OPENING_BALANCE],
|
AccountType::INITIAL_BALANCE => [TransactionTypeModel::OPENING_BALANCE],
|
||||||
AccountType::RECONCILIATION => [TransactionTypeModel::RECONCILIATION],
|
AccountType::RECONCILIATION => [TransactionTypeModel::RECONCILIATION],
|
||||||
AccountType::LIABILITY_CREDIT => [TransactionTypeModel::LIABILITY_CREDIT],
|
AccountType::LIABILITY_CREDIT => [TransactionTypeModel::LIABILITY_CREDIT],
|
||||||
],
|
],
|
||||||
'destination' => [
|
'destination' => [
|
||||||
AccountType::ASSET => [TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER, TransactionTypeModel::OPENING_BALANCE,
|
AccountType::ASSET => [
|
||||||
TransactionTypeModel::RECONCILIATION,],
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
|
TransactionTypeModel::TRANSFER,
|
||||||
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
|
TransactionTypeModel::RECONCILIATION,
|
||||||
|
],
|
||||||
AccountType::EXPENSE => [TransactionTypeModel::WITHDRAWAL],
|
AccountType::EXPENSE => [TransactionTypeModel::WITHDRAWAL],
|
||||||
AccountType::REVENUE => [], // is not allowed as destination.
|
AccountType::REVENUE => [], // is not allowed as destination.
|
||||||
AccountType::LOAN => [TransactionTypeModel::WITHDRAWAL, TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER,
|
AccountType::LOAN => [
|
||||||
TransactionTypeModel::OPENING_BALANCE,],
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
AccountType::DEBT => [TransactionTypeModel::WITHDRAWAL, TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER,
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
TransactionTypeModel::OPENING_BALANCE,],
|
TransactionTypeModel::TRANSFER,
|
||||||
AccountType::MORTGAGE => [TransactionTypeModel::WITHDRAWAL, TransactionTypeEnum::DEPOSIT->value, TransactionTypeModel::TRANSFER,
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
TransactionTypeModel::OPENING_BALANCE,],
|
],
|
||||||
|
AccountType::DEBT => [
|
||||||
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
|
TransactionTypeModel::TRANSFER,
|
||||||
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
|
],
|
||||||
|
AccountType::MORTGAGE => [
|
||||||
|
TransactionTypeModel::WITHDRAWAL,
|
||||||
|
TransactionTypeEnum::DEPOSIT->value,
|
||||||
|
TransactionTypeModel::TRANSFER,
|
||||||
|
TransactionTypeModel::OPENING_BALANCE,
|
||||||
|
],
|
||||||
AccountType::INITIAL_BALANCE => [TransactionTypeModel::OPENING_BALANCE],
|
AccountType::INITIAL_BALANCE => [TransactionTypeModel::OPENING_BALANCE],
|
||||||
AccountType::RECONCILIATION => [TransactionTypeModel::RECONCILIATION],
|
AccountType::RECONCILIATION => [TransactionTypeModel::RECONCILIATION],
|
||||||
AccountType::LIABILITY_CREDIT => [], // is not allowed as a destination
|
AccountType::LIABILITY_CREDIT => [], // is not allowed as a destination
|
||||||
@@ -727,23 +837,40 @@ return [
|
|||||||
AccountType::LIABILITY_CREDIT => [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
AccountType::LIABILITY_CREDIT => [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
// if you add fields to this array, dont forget to update the export routine (ExportDataGenerator).
|
// if you add fields to this array, don't forget to update the export routine (ExportDataGenerator).
|
||||||
'journal_meta_fields' => [
|
'journal_meta_fields' => [
|
||||||
// sepa
|
// sepa
|
||||||
'sepa_cc', 'sepa_ct_op', 'sepa_ct_id',
|
'sepa_cc',
|
||||||
'sepa_db', 'sepa_country', 'sepa_ep',
|
'sepa_ct_op',
|
||||||
'sepa_ci', 'sepa_batch_id', 'external_url',
|
'sepa_ct_id',
|
||||||
|
'sepa_db',
|
||||||
|
'sepa_country',
|
||||||
|
'sepa_ep',
|
||||||
|
'sepa_ci',
|
||||||
|
'sepa_batch_id',
|
||||||
|
'external_url',
|
||||||
|
|
||||||
// dates
|
// dates
|
||||||
'interest_date', 'book_date', 'process_date',
|
'interest_date',
|
||||||
'due_date', 'payment_date', 'invoice_date',
|
'book_date',
|
||||||
|
'process_date',
|
||||||
|
'due_date',
|
||||||
|
'payment_date',
|
||||||
|
'invoice_date',
|
||||||
|
|
||||||
// others
|
// others
|
||||||
'recurrence_id', 'internal_reference', 'bunq_payment_id',
|
'recurrence_id',
|
||||||
'import_hash', 'import_hash_v2', 'external_id', 'original_source',
|
'internal_reference',
|
||||||
|
'bunq_payment_id',
|
||||||
|
'import_hash',
|
||||||
|
'import_hash_v2',
|
||||||
|
'external_id',
|
||||||
|
'original_source',
|
||||||
|
|
||||||
// recurring transactions
|
// recurring transactions
|
||||||
'recurrence_total', 'recurrence_count',
|
'recurrence_total',
|
||||||
|
'recurrence_count',
|
||||||
|
'recurrence_date',
|
||||||
],
|
],
|
||||||
'webhooks' => [
|
'webhooks' => [
|
||||||
'max_attempts' => env('WEBHOOK_MAX_ATTEMPTS', 3),
|
'max_attempts' => env('WEBHOOK_MAX_ATTEMPTS', 3),
|
||||||
|
@@ -2447,6 +2447,8 @@ return [
|
|||||||
'no_bills_create_default' => 'Create a bill',
|
'no_bills_create_default' => 'Create a bill',
|
||||||
|
|
||||||
// recurring transactions
|
// recurring transactions
|
||||||
|
'create_right_now' => 'Create right now',
|
||||||
|
'no_new_transaction_in_recurrence' => 'No new transaction was created. Perhaps it was already fired for this date?',
|
||||||
'recurrences' => 'Recurring transactions',
|
'recurrences' => 'Recurring transactions',
|
||||||
'repeat_until_in_past' => 'This recurring transaction stopped repeating on :date.',
|
'repeat_until_in_past' => 'This recurring transaction stopped repeating on :date.',
|
||||||
'recurring_calendar_view' => 'Calendar',
|
'recurring_calendar_view' => 'Calendar',
|
||||||
|
@@ -37,8 +37,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="{{ route('recurring.edit', [array.id]) }}" class="btn btn-sm btn-default"><span class="fa fa-pencil"></span> {{ 'edit'|_ }}</a>
|
<a href="{{ route('recurring.edit', [array.id]) }}" class="btn btn-sm btn-default"><span
|
||||||
<a href="{{ route('recurring.delete', [array.id]) }}" class="btn btn-sm btn-danger">{{ 'delete'|_ }} <span class="fa fa-trash"></span></a>
|
class="fa fa-pencil"></span> {{ 'edit'|_ }}</a>
|
||||||
|
<a href="{{ route('recurring.delete', [array.id]) }}" class="btn btn-sm btn-danger">{{ 'delete'|_ }}
|
||||||
|
<span class="fa fa-trash"></span></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -57,24 +59,37 @@
|
|||||||
{{ trans('firefly.repeat_until_in_past', {date: array.repeat_until.isoFormat(monthAndDayFormat) }) }}
|
{{ trans('firefly.repeat_until_in_past', {date: array.repeat_until.isoFormat(monthAndDayFormat) }) }}
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ul>
|
|
||||||
{% for rep in array.repetitions %}
|
{% for rep in array.repetitions %}
|
||||||
<li>
|
<p>
|
||||||
{{ rep.description }}
|
<strong>{{ rep.description }}
|
||||||
{% if rep.repetition_skip == 1 %}
|
{% if rep.repetition_skip == 1 %}
|
||||||
({{ trans('firefly.recurring_skips_one')|lower }})
|
({{ trans('firefly.recurring_skips_one')|lower }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if rep.repetition_skip > 1 %}
|
{% if rep.repetition_skip > 1 %}
|
||||||
({{ trans('firefly.recurring_skips_more', {count: rep.repetition_skip})|lower }})
|
({{ trans('firefly.recurring_skips_more', {count: rep.repetition_skip})|lower }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ul>
|
</strong>
|
||||||
{% for occ in rep.occurrences %}
|
</p>
|
||||||
<li>{{ occ.isoFormat(trans('config.month_and_date_day_js')) }}</li>
|
<table class="table">
|
||||||
{% endfor %}
|
<tbody>
|
||||||
</ul>
|
{% for occ in rep.occurrences %}
|
||||||
</li>
|
<tr>
|
||||||
|
<td>{{ occ.date.isoFormat(trans('config.month_and_date_day_js')) }}</td>
|
||||||
|
<td>
|
||||||
|
{% if not occ.fired %}
|
||||||
|
<form action="{{ route('recurring.trigger', [recurrence.id]) }}" method="post" style="display: inline;">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||||
|
<input type="hidden" name="date" value="{{ occ.date.isoFormat('YYYY-MM-DD') }}">
|
||||||
|
<input type="submit" name="submit" value="{{ 'create_right_now'|_ }}"
|
||||||
|
class="btn btn-sm btn-default">
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer">
|
<div class="box-footer">
|
||||||
<small>
|
<small>
|
||||||
@@ -175,11 +190,13 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
<link rel="stylesheet" href="v1/css/bootstrap-sortable.css?v={{ FF_VERSION }}" type="text/css" media="all" nonce="{{ JS_NONCE }}">
|
<link rel="stylesheet" href="v1/css/bootstrap-sortable.css?v={{ FF_VERSION }}" type="text/css" media="all"
|
||||||
|
nonce="{{ JS_NONCE }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script type="text/javascript" src="v1/js/lib/bootstrap-sortable.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
<script type="text/javascript" src="v1/js/lib/bootstrap-sortable.js?v={{ FF_VERSION }}"
|
||||||
|
nonce="{{ JS_NONCE }}"></script>
|
||||||
{# required for groups.twig #}
|
{# required for groups.twig #}
|
||||||
<script type="text/javascript" src="v1/js/ff/list/groups.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
<script type="text/javascript" src="v1/js/ff/list/groups.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -718,6 +718,7 @@ Route::group(
|
|||||||
Route::post('store', ['uses' => 'Recurring\CreateController@store', 'as' => 'store']);
|
Route::post('store', ['uses' => 'Recurring\CreateController@store', 'as' => 'store']);
|
||||||
Route::post('update/{recurrence}', ['uses' => 'Recurring\EditController@update', 'as' => 'update']);
|
Route::post('update/{recurrence}', ['uses' => 'Recurring\EditController@update', 'as' => 'update']);
|
||||||
Route::post('destroy/{recurrence}', ['uses' => 'Recurring\DeleteController@destroy', 'as' => 'destroy']);
|
Route::post('destroy/{recurrence}', ['uses' => 'Recurring\DeleteController@destroy', 'as' => 'destroy']);
|
||||||
|
Route::post('trigger/{recurrence}', ['uses' => 'Recurring\TriggerController@trigger', 'as' => 'trigger']);
|
||||||
|
|
||||||
// JSON routes:
|
// JSON routes:
|
||||||
Route::get('events', ['uses' => 'Json\RecurrenceController@events', 'as' => 'events']);
|
Route::get('events', ['uses' => 'Json\RecurrenceController@events', 'as' => 'events']);
|
||||||
|
Reference in New Issue
Block a user