mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-12-25 08:21:08 -06:00
First attempt at job to create transactions for recurring transactions.
This commit is contained in:
parent
636cd84f4f
commit
db1c27d833
@ -24,8 +24,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Jobs\CreateRecurringTransactions;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* File to make sure commnds work.
|
||||
@ -58,7 +63,43 @@ class Kernel extends ConsoleKernel
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$schedule->call(
|
||||
function () {
|
||||
// run for the entirety of 2018, just to see what happens
|
||||
$start = new Carbon('2018-01-01');
|
||||
$end = new Carbon('2018-12-31');
|
||||
while ($start <= $end) {
|
||||
Log::info(sprintf('Now at %s', $start->format('D Y-m-d')));
|
||||
$job = new CreateRecurringTransactions(clone $start);
|
||||
$job->handle();
|
||||
$start->addDay();
|
||||
}
|
||||
|
||||
}
|
||||
)->everyMinute();
|
||||
|
||||
//$schedule->job(new CreateRecurringTransactions(new Carbon))->everyMinute();
|
||||
|
||||
//$schedule->job(new CreateRecurringTransactions(new Carbon))->everyMinute();
|
||||
|
||||
|
||||
// $schedule->call(
|
||||
// function () {
|
||||
// // command to do something
|
||||
// Log::debug('Schedule creation of transactions yaay!');
|
||||
// }
|
||||
// )->daily();
|
||||
//
|
||||
// $schedule->call(
|
||||
// function () {
|
||||
// // command to do something
|
||||
// Log::debug('Every minute!');
|
||||
// }
|
||||
// )->everyMinute()
|
||||
// ->emailOutputTo('thege');
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
|
||||
use FireflyIII\Services\Internal\Support\TransactionTypeTrait;
|
||||
use FireflyIII\User;
|
||||
@ -100,7 +99,8 @@ class TransactionJournalFactory
|
||||
|
||||
// store date meta fields (if present):
|
||||
$fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
|
||||
'due_date', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2', 'external_id'];
|
||||
'due_date', 'recurrence_id', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2',
|
||||
'external_id'];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$this->storeMeta($journal, $data, $field);
|
||||
|
@ -76,6 +76,8 @@ class EditController extends Controller
|
||||
*/
|
||||
public function edit(Request $request, Recurrence $recurrence)
|
||||
{
|
||||
|
||||
|
||||
// use transformer:
|
||||
$transformer = new RecurrenceTransformer(new ParameterBag);
|
||||
$array = $transformer->transform($recurrence);
|
||||
@ -86,6 +88,7 @@ class EditController extends Controller
|
||||
// todo handle old repetition type as well.
|
||||
|
||||
|
||||
|
||||
/** @var RecurrenceRepetition $repetition */
|
||||
$repetition = $recurrence->recurrenceRepetitions()->first();
|
||||
$currentRepetitionType = $repetition->repetition_type;
|
||||
@ -116,13 +119,12 @@ class EditController extends Controller
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
// $hasOldInput = false;
|
||||
$preFilled = [
|
||||
'transaction_type' => strtolower($recurrence->transactionType->type),
|
||||
'active' => $hasOldInput ? (bool)$request->old('active') : $recurrence->active,
|
||||
'apply_rules' => $hasOldInput ? (bool)$request->old('apply_rules') : $recurrence->apply_rules,
|
||||
];
|
||||
$request->flash('preFilled', $preFilled);
|
||||
|
||||
|
||||
return view('recurring.edit', compact('recurrence', 'array', 'budgets', 'preFilled', 'currentRepetitionType', 'repetitionEnd', 'repetitionEnds'));
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ class IndexController extends Controller
|
||||
{
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$collection = $this->recurring->getActive();
|
||||
$collection = $this->recurring->get();
|
||||
|
||||
// TODO: split collection into pages
|
||||
|
||||
|
321
app/Jobs/CreateRecurringTransactions.php
Normal file
321
app/Jobs/CreateRecurringTransactions.php
Normal file
@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class CreateRecurringTransactions
|
||||
*/
|
||||
class CreateRecurringTransactions implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/** @var Carbon */
|
||||
private $date;
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $journalRepository;
|
||||
/** @var RecurringRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param Carbon $date
|
||||
*/
|
||||
public function __construct(Carbon $date)
|
||||
{
|
||||
$date->startOfDay();
|
||||
$this->date = $date;
|
||||
$this->repository = app(RecurringRepositoryInterface::class);
|
||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* TODO check number of repetitions.
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
Log::debug('Now at start of CreateRecurringTransactions() job.');
|
||||
$recurrences = $this->repository->getAll();
|
||||
Log::debug(sprintf('Count of collection is %d', $recurrences->count()));
|
||||
|
||||
/** @var Collection $filtered */
|
||||
$filtered = $recurrences->filter(
|
||||
function (Recurrence $recurrence) {
|
||||
return $this->validRecurrence($recurrence);
|
||||
|
||||
}
|
||||
);
|
||||
Log::debug(sprintf('Left after filtering is %d', $filtered->count()));
|
||||
/** @var Recurrence $recurrence */
|
||||
foreach ($filtered as $recurrence) {
|
||||
$this->repository->setUser($recurrence->user);
|
||||
$this->journalRepository->setUser($recurrence->user);
|
||||
Log::debug(sprintf('Now at recurrence #%d', $recurrence->id));
|
||||
$this->handleRepetitions($recurrence);
|
||||
Log::debug(sprintf('Done with recurrence #%c', $recurrence->id));
|
||||
}
|
||||
Log::debug('Done with handle()');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return recurring transaction is active.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function active(Recurrence $recurrence): bool
|
||||
{
|
||||
return $recurrence->active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $occurrences
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function debugArray(array $occurrences): array
|
||||
{
|
||||
$return = [];
|
||||
foreach ($occurrences as $entry) {
|
||||
$return[] = $entry->format('Y-m-d');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
private function getStartDate(Recurrence $recurrence): Carbon
|
||||
{
|
||||
$startDate = clone $recurrence->first_date;
|
||||
if (null !== $recurrence->latest_date && $recurrence->latest_date->gte($startDate)) {
|
||||
$startDate = clone $recurrence->latest_date;
|
||||
// jump to a day later.
|
||||
$startDate->addDay();
|
||||
|
||||
}
|
||||
|
||||
return $startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(Recurrence $recurrence): array
|
||||
{
|
||||
$transactions = $recurrence->recurrenceTransactions()->get();
|
||||
$return = [];
|
||||
/** @var RecurrenceTransaction $transaction */
|
||||
foreach ($transactions as $index => $transaction) {
|
||||
$single = [
|
||||
'currency_id' => $transaction->transaction_currency_id,
|
||||
'currency_code' => null,
|
||||
'description' => null,
|
||||
'amount' => $transaction->amount,
|
||||
'budget_id' => $this->repository->getBudget($transaction),
|
||||
'budget_name' => null,
|
||||
'category_id' => null,
|
||||
'category_name' => $this->repository->getCategory($transaction),
|
||||
'source_id' => $transaction->source_account_id,
|
||||
'source_name' => null,
|
||||
'destination_id' => $transaction->destination_account_id,
|
||||
'destination_name' => null,
|
||||
'foreign_currency_id' => $transaction->foreign_currency_id,
|
||||
'foreign_currency_code' => null,
|
||||
'foreign_amount' => $transaction->foreign_amount,
|
||||
'reconciled' => false,
|
||||
'identifier' => $index,
|
||||
];
|
||||
$return[] = $single;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
* @param array $occurrences
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function handleOccurrences(Recurrence $recurrence, array $occurrences): void
|
||||
{
|
||||
/** @var Carbon $date */
|
||||
foreach ($occurrences as $date) {
|
||||
Log::debug(sprintf('Now at date %s.', $date->format('Y-m-d')));
|
||||
if ($date->ne($this->date)) {
|
||||
Log::debug(sprintf('%s is not not today (%s)', $date->format('Y-m-d'), $this->date->format('Y-m-d')));
|
||||
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('%s IS today (%s)', $date->format('Y-m-d'), $this->date->format('Y-m-d')));
|
||||
|
||||
// create transaction array and send to factory.
|
||||
$array = [
|
||||
'type' => $recurrence->transactionType->type,
|
||||
'date' => $date,
|
||||
'tags' => $this->repository->getTags($recurrence),
|
||||
'user' => $recurrence->user_id,
|
||||
'notes' => trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]),
|
||||
|
||||
// journal data:
|
||||
'description' => $recurrence->recurrenceTransactions()->first()->description,
|
||||
'piggy_bank_id' => null,
|
||||
'piggy_bank_name' => null,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'recurrence_id' => $recurrence->id,
|
||||
|
||||
// transaction data:
|
||||
'transactions' => $this->getTransactionData($recurrence),
|
||||
];
|
||||
$journal = $this->journalRepository->store($array);
|
||||
Log::info(sprintf('Created new journal #%d', $journal->id));
|
||||
// update recurring thing:
|
||||
$recurrence->latest_date = $date;
|
||||
$recurrence->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Separate method that will loop all repetitions and do something with it:
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function handleRepetitions(Recurrence $recurrence): void
|
||||
{
|
||||
/** @var RecurrenceRepetition $repetition */
|
||||
foreach ($recurrence->recurrenceRepetitions as $repetition) {
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Now repeating %s with value "%s", skips every %d time(s)', $repetition->repetition_type, $repetition->repetition_moment,
|
||||
$repetition->repetition_skip
|
||||
)
|
||||
);
|
||||
|
||||
// start looping from $startDate to today perhaps we have a hit?
|
||||
$occurrences = $this->repository->getOccurrencesInRange($repetition, $recurrence->first_date, $this->date);
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Calculated %d occurrences between %s and %s', \count($occurrences), $recurrence->first_date->format('Y-m-d'), $this->date->format('Y-m-d')
|
||||
), $this->debugArray($occurrences)
|
||||
);
|
||||
|
||||
$this->handleOccurrences($recurrence, $occurrences);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasFiredToday(Recurrence $recurrence): bool
|
||||
{
|
||||
return null !== $recurrence->latest_date && $recurrence->latest_date->eq($this->date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $recurrence
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasNotStartedYet(Recurrence $recurrence): bool
|
||||
{
|
||||
$startDate = $this->getStartDate($recurrence);
|
||||
|
||||
return $startDate->gt($this->date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the $repeat_until date is in the past.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function repeatUntilHasPassed(Recurrence $recurrence): bool
|
||||
{
|
||||
// date has passed
|
||||
return null !== $recurrence->repeat_until && $recurrence->repeat_until->lt($this->date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validRecurrence(Recurrence $recurrence): bool
|
||||
{
|
||||
// is not active.
|
||||
if (!$this->active($recurrence)) {
|
||||
Log::info(sprintf('Recurrence #%d is not active. Skipped.', $recurrence->id));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// is no longer running
|
||||
if ($this->repeatUntilHasPassed($recurrence)) {
|
||||
Log::info(
|
||||
sprintf(
|
||||
'Recurrence #%d was set to run until %s, and today\'s date is %s. Skipped.',
|
||||
$recurrence->id,
|
||||
$recurrence->repeat_until->format('Y-m-d'),
|
||||
$this->date->format('Y-m-d')
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// first_date is in the future
|
||||
if ($this->hasNotStartedYet($recurrence)) {
|
||||
Log::info(
|
||||
sprintf(
|
||||
'Recurrence #%d is set to run on %s, and today\'s date is %s. Skipped.',
|
||||
$recurrence->id,
|
||||
$recurrence->first_date->format('Y-m-d'),
|
||||
$this->date->format('Y-m-d')
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// already fired today (with success):
|
||||
if ($this->hasFiredToday($recurrence)) {
|
||||
Log::info(sprintf('Recurrence #%d has already fired today. Skipped.', $recurrence->id));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
@ -29,11 +29,14 @@ use FireflyIII\Factory\RecurrenceFactory;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceMeta;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
use FireflyIII\Services\Internal\Update\RecurrenceUpdateService;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use Log;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -49,11 +52,68 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActive(): Collection
|
||||
public function get(): Collection
|
||||
{
|
||||
return $this->user->recurrences()->with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])->where(
|
||||
'active', 1
|
||||
)->get();
|
||||
return $this->user->recurrences()
|
||||
->with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
|
||||
->orderBy('active', 'DESC')
|
||||
->orderBy('title', 'ASC')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ALL recurring transactions.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAll(): Collection
|
||||
{
|
||||
// grab ALL recurring transactions:
|
||||
return Recurrence
|
||||
::with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
|
||||
->orderBy('active', 'DESC')
|
||||
->orderBy('title', 'ASC')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the budget ID from a recurring transaction transaction.
|
||||
*
|
||||
* @param RecurrenceTransaction $recurrenceTransaction
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function getBudget(RecurrenceTransaction $recurrenceTransaction): ?int
|
||||
{
|
||||
$return = 0;
|
||||
/** @var RecurrenceTransactionMeta $meta */
|
||||
foreach ($recurrenceTransaction->recurrenceTransactionMeta as $meta) {
|
||||
if ($meta->name === 'budget_id') {
|
||||
$return = (int)$meta->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $return === 0 ? null : $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the category from a recurring transaction transaction.
|
||||
*
|
||||
* @param RecurrenceTransaction $recurrenceTransaction
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getCategory(RecurrenceTransaction $recurrenceTransaction): ?string
|
||||
{
|
||||
$return = '';
|
||||
/** @var RecurrenceTransactionMeta $meta */
|
||||
foreach ($recurrenceTransaction->recurrenceTransactionMeta as $meta) {
|
||||
if ($meta->name === 'category_name') {
|
||||
$return = (string)$meta->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $return === '' ? null : $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,6 +152,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
$mutator->startOfDay();
|
||||
$skipMod = $repetition->repetition_skip + 1;
|
||||
$attempts = 0;
|
||||
Log::debug(sprintf('Calculating occurrences for rep type "%s"', $repetition->repetition_type));
|
||||
switch ($repetition->repetition_type) {
|
||||
default:
|
||||
throw new FireflyException(
|
||||
@ -120,7 +181,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
$dayDifference = $dayOfWeek - $mutator->dayOfWeekIso;
|
||||
$mutator->addDays($dayDifference);
|
||||
while ($mutator <= $end) {
|
||||
if ($attempts % $skipMod === 0) {
|
||||
if ($attempts % $skipMod === 0 && $start->lte($mutator) && $end->gte($mutator)) {
|
||||
$return[] = clone $mutator;
|
||||
}
|
||||
$attempts++;
|
||||
@ -129,19 +190,31 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
break;
|
||||
case 'monthly':
|
||||
$dayOfMonth = (int)$repetition->repetition_moment;
|
||||
Log::debug(sprintf('Day of month in repetition is %d', $dayOfMonth));
|
||||
Log::debug(sprintf('Start is %s.', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End is %s.', $end->format('Y-m-d')));
|
||||
if ($mutator->day > $dayOfMonth) {
|
||||
Log::debug('Add a month.');
|
||||
// day has passed already, add a month.
|
||||
$mutator->addMonth();
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Start is now %s.', $mutator->format('Y-m-d')));
|
||||
Log::debug('Start loop.');
|
||||
while ($mutator < $end) {
|
||||
Log::debug(sprintf('Mutator is now %s.', $mutator->format('Y-m-d')));
|
||||
$domCorrected = min($dayOfMonth, $mutator->daysInMonth);
|
||||
Log::debug(sprintf('DoM corrected is %d', $domCorrected));
|
||||
$mutator->day = $domCorrected;
|
||||
if ($attempts % $skipMod === 0) {
|
||||
Log::debug(sprintf('Mutator is now %s.', $mutator->format('Y-m-d')));
|
||||
Log::debug(sprintf('$attempts %% $skipMod === 0 is %s', var_export($attempts % $skipMod === 0, true)));
|
||||
Log::debug(sprintf('$start->lte($mutator) is %s', var_export($start->lte($mutator), true)));
|
||||
Log::debug(sprintf('$end->gte($mutator) is %s', var_export($end->gte($mutator), true)));
|
||||
if ($attempts % $skipMod === 0 && $start->lte($mutator) && $end->gte($mutator)) {
|
||||
Log::debug(sprintf('ADD %s to return!', $mutator->format('Y-m-d')));
|
||||
$return[] = clone $mutator;
|
||||
}
|
||||
$attempts++;
|
||||
$mutator->endOfMonth()->addDay();
|
||||
$mutator->endOfMonth()->startOfDay()->addDay();
|
||||
}
|
||||
break;
|
||||
case 'ndom':
|
||||
@ -180,6 +253,26 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tags from the recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(Recurrence $recurrence): array
|
||||
{
|
||||
$tags = [];
|
||||
/** @var RecurrenceMeta $meta */
|
||||
foreach ($recurrence->recurrenceMeta as $meta) {
|
||||
if ($meta->name === 'tags' && '' !== $meta->value) {
|
||||
$tags = explode(',', $meta->value);
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the next X iterations starting on the date given in $date.
|
||||
*
|
||||
@ -377,6 +470,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Recurrence
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function update(Recurrence $recurrence, array $data): Recurrence
|
||||
{
|
||||
|
@ -27,6 +27,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@ -43,7 +44,31 @@ interface RecurringRepositoryInterface
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActive(): Collection;
|
||||
public function get(): Collection;
|
||||
|
||||
/**
|
||||
* Get ALL recurring transactions.
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAll(): Collection;
|
||||
|
||||
/**
|
||||
* Get the category from a recurring transaction transaction.
|
||||
*
|
||||
* @param RecurrenceTransaction $recurrenceTransaction
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getCategory(RecurrenceTransaction $recurrenceTransaction): ?string;
|
||||
|
||||
/**
|
||||
* Get the budget ID from a recurring transaction transaction.
|
||||
*
|
||||
* @param RecurrenceTransaction $recurrenceTransaction
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function getBudget(RecurrenceTransaction $recurrenceTransaction): ?int;
|
||||
|
||||
/**
|
||||
* Get the notes.
|
||||
@ -67,6 +92,15 @@ interface RecurringRepositoryInterface
|
||||
*/
|
||||
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array;
|
||||
|
||||
/**
|
||||
* Get the tags from the recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(Recurrence $recurrence): array;
|
||||
|
||||
/**
|
||||
* Calculate the next X iterations starting on the date given in $date.
|
||||
* Returns an array of Carbon objects.
|
||||
@ -98,6 +132,7 @@ interface RecurringRepositoryInterface
|
||||
|
||||
/**
|
||||
* Store a new recurring transaction.
|
||||
*\
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
|
@ -515,16 +515,7 @@ class ExpandedForm
|
||||
*/
|
||||
public function optionsList(string $type, string $name): string
|
||||
{
|
||||
$previousValue = null;
|
||||
|
||||
try {
|
||||
$previousValue = request()->old('post_submit_action');
|
||||
} catch (RuntimeException $e) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
$previousValue = $previousValue ?? 'store';
|
||||
$html = view('form.options', compact('type', 'name', 'previousValue'))->render();
|
||||
$html = view('form.options', compact('type', 'name'))->render();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
50
composer.lock
generated
50
composer.lock
generated
@ -1150,16 +1150,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.6.24",
|
||||
"version": "v5.6.25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "56290edeb0d8051826d40b4cbd8ed3c30348b2b5"
|
||||
"reference": "a15efe4fbcd6b38ea76edc5c8939ffde4f4c7b7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/56290edeb0d8051826d40b4cbd8ed3c30348b2b5",
|
||||
"reference": "56290edeb0d8051826d40b4cbd8ed3c30348b2b5",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/a15efe4fbcd6b38ea76edc5c8939ffde4f4c7b7f",
|
||||
"reference": "a15efe4fbcd6b38ea76edc5c8939ffde4f4c7b7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1285,7 +1285,7 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2018-06-04T14:51:03+00:00"
|
||||
"time": "2018-06-12T14:39:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
@ -4457,16 +4457,16 @@
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6"
|
||||
"reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/478465659fd987669df0bd8a9bf22a8710e5f1b6",
|
||||
"reference": "478465659fd987669df0bd8a9bf22a8710e5f1b6",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
|
||||
"reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4501,7 +4501,7 @@
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"time": "2018-05-29T17:25:09+00:00"
|
||||
"time": "2018-06-11T23:09:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -4968,16 +4968,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "e20525b0c2945c7c317fff95660698cb3d2a53bc"
|
||||
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/e20525b0c2945c7c317fff95660698cb3d2a53bc",
|
||||
"reference": "e20525b0c2945c7c317fff95660698cb3d2a53bc",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c",
|
||||
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -5011,7 +5011,7 @@
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2018-05-28T12:13:49+00:00"
|
||||
"time": "2018-06-11T11:44:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
@ -5450,16 +5450,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5"
|
||||
"reference": "591a30922f54656695e59b1f39501aec513403da"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ed5fd2281113729f1ebcc64d101ad66028aeb3d5",
|
||||
"reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/591a30922f54656695e59b1f39501aec513403da",
|
||||
"reference": "591a30922f54656695e59b1f39501aec513403da",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -5510,20 +5510,20 @@
|
||||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2018-04-18T13:33:00+00:00"
|
||||
"time": "2018-06-14T15:05:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8"
|
||||
"reference": "366541b989927187c4ca70490a35615d3fef2dce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8",
|
||||
"reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce",
|
||||
"reference": "366541b989927187c4ca70490a35615d3fef2dce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -5566,7 +5566,7 @@
|
||||
"unidiff",
|
||||
"unified diff"
|
||||
],
|
||||
"time": "2018-02-01T13:45:15+00:00"
|
||||
"time": "2018-06-10T07:54:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
|
15
public/js/ff/recurring/edit.js
vendored
15
public/js/ff/recurring/edit.js
vendored
@ -100,11 +100,19 @@ function respondToRepetitionEnd() {
|
||||
}
|
||||
|
||||
function respondToFirstDateChange() {
|
||||
//
|
||||
var obj = $('#ffInput_first_date');
|
||||
var select = $('#ffInput_repetition_type');
|
||||
var date = obj.val();
|
||||
select.prop('disabled', true);
|
||||
$.getJSON(suggestUri, {date: date,past:true}).fail(function () {
|
||||
|
||||
// preselected value:
|
||||
var preSelected = currentRepetitionType;
|
||||
if(preSelected === '') {
|
||||
preSelected = select.val();
|
||||
}
|
||||
|
||||
$.getJSON(suggestUri, {date: date,pre_select: preSelected,past:true}).fail(function () {
|
||||
console.error('Could not load repetition suggestions');
|
||||
alert('Could not load repetition suggestions');
|
||||
}).done(parseRepetitionSuggestions);
|
||||
@ -117,8 +125,9 @@ function parseRepetitionSuggestions(data) {
|
||||
var opt;
|
||||
for (var k in data) {
|
||||
if (data.hasOwnProperty(k)) {
|
||||
opt = $('<option>').val(k).attr('label', data[k]).text(data[k]);
|
||||
if(k === currentRepetitionType) {
|
||||
console.log('label: ' + data[k].label + ', selected: ' + data[k].selected);
|
||||
opt = $('<option>').val(k).attr('label', data[k].label).text(data[k].label);
|
||||
if(data[k].selected) {
|
||||
opt.attr('selected','selected');
|
||||
}
|
||||
select.append(opt);
|
||||
|
@ -100,11 +100,7 @@ There are many ways to run Firefly III
|
||||
5. You can [deploy to Sandstorm.io](https://apps.sandstorm.io/app/uws252ya9mep4t77tevn85333xzsgrpgth8q4y1rhknn1hammw70)
|
||||
6. You can [install it using Softaculous](https://softaculous.com/). These guys even have made [another demo site](http://www.softaculous.com/softaculous/apps/others/Firefly_III)!
|
||||
7. You can [install it using AMPPS](https://www.ampps.com/)
|
||||
8. Install it on [YunoHost](https://yunohost.org).
|
||||
|
||||
[![Install Firefly-III with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=firefly-iii)
|
||||
|
||||
See [here.](https://github.com/YunoHost-Apps/Firefly-III_ynh).
|
||||
8. You can [install it with YunoHost](https://install-app.yunohost.org/?app=firefly-iii).
|
||||
9. *Even more options are on the way!*
|
||||
|
||||
### Update your instance
|
||||
|
@ -1223,33 +1223,41 @@ return [
|
||||
'overview_for_recurrence' => 'Overview for recurring transaction ":title"',
|
||||
'warning_duplicates_repetitions' => 'In rare instances, dates appear twice in this list. This can happen when multiple repetitions collide. Firefly III will always generate one transaction per day.',
|
||||
'created_transactions' => 'Related transactions',
|
||||
'expected_transactions' => 'Expected transactions',
|
||||
'recurring_meta_field_tags' => 'Tags',
|
||||
'recurring_meta_field_notes' => 'Notes',
|
||||
'recurring_meta_field_bill_id' => 'Bill',
|
||||
'recurring_meta_field_piggy_bank_id' => 'Piggy bank',
|
||||
'create_new_recurrence' => 'Create new recurring transaction',
|
||||
'help_first_date' => 'Indicate the first expected recurrence. This must be in the future.',
|
||||
'help_first_date_no_past' => 'Indicate the first expected recurrence. Firefly III will not create transactions in the past.',
|
||||
'no_currency' => '(no currency)',
|
||||
'mandatory_for_recurring' => 'Mandatory recurrence information',
|
||||
'mandatory_for_transaction' => 'Mandatory transaction information',
|
||||
'optional_for_recurring' => 'Optional recurrence information',
|
||||
'optional_for_transaction' => 'Optional transaction information',
|
||||
'change_date_other_options' => 'Change the "first date" to see more options.',
|
||||
'mandatory_fields_for_tranaction' => 'The values here will end up in the transaction(s) being created',
|
||||
'click_for_calendar' => 'Click here for a calendar that shows you when the transaction would repeat.',
|
||||
'repeat_forever' => 'Repeat forever',
|
||||
'repeat_until_date' => 'Repeat until date',
|
||||
'repeat_times' => 'Repeat a number of times',
|
||||
'recurring_skips_one' => 'Every other',
|
||||
'recurring_skips_more' => 'Skips :count occurrences',
|
||||
'store_new_recurrence' => 'Store recurring transaction',
|
||||
'stored_new_recurrence' => 'Recurring transaction ":title" stored successfully.',
|
||||
'edit_recurrence' => 'Edit recurring transaction ":title"',
|
||||
'recurring_repeats_until' => 'Repeats until :date',
|
||||
'recurring_repeats_forever' => 'Repeats forever',
|
||||
'recurring_repeats_x_times' => 'Repeats :count time(s)',
|
||||
'update_recurrence' => 'Update recurring transaction',
|
||||
'updated_recurrence' => 'Updated recurring transaction ":title"',
|
||||
'expected_Withdrawals' => 'Expected withdrawals',
|
||||
'expected_Deposits' => 'Expected deposits',
|
||||
'expected_Transfers' => 'Expected transfers',
|
||||
'created_Withdrawals' => 'Created withdrawals',
|
||||
'created_Deposits' => 'Created deposits',
|
||||
'created_Transfers' => 'Created transfers',
|
||||
'created_from_recurrence' => 'Created from recurring transaction ":title" (#:id)',
|
||||
|
||||
'recurring_meta_field_tags' => 'Tags',
|
||||
'recurring_meta_field_notes' => 'Notes',
|
||||
'recurring_meta_field_bill_id' => 'Bill',
|
||||
'recurring_meta_field_piggy_bank_id' => 'Piggy bank',
|
||||
'create_new_recurrence' => 'Create new recurring transaction',
|
||||
'help_first_date' => 'Indicate the first expected recurrence. This must be in the future.',
|
||||
'help_first_date_no_past' => 'Indicate the first expected recurrence. Firefly III will not create transactions in the past.',
|
||||
'no_currency' => '(no currency)',
|
||||
'mandatory_for_recurring' => 'Mandatory recurrence information',
|
||||
'mandatory_for_transaction' => 'Mandatory transaction information',
|
||||
'optional_for_recurring' => 'Optional recurrence information',
|
||||
'optional_for_transaction' => 'Optional transaction information',
|
||||
'change_date_other_options' => 'Change the "first date" to see more options.',
|
||||
'mandatory_fields_for_tranaction' => 'The values here will end up in the transaction(s) being created',
|
||||
'click_for_calendar' => 'Click here for a calendar that shows you when the transaction would repeat.',
|
||||
'repeat_forever' => 'Repeat forever',
|
||||
'repeat_until_date' => 'Repeat until date',
|
||||
'repeat_times' => 'Repeat a number of times',
|
||||
'recurring_skips_one' => 'Every other',
|
||||
'recurring_skips_more' => 'Skips :count occurrences',
|
||||
'store_new_recurrence' => 'Store recurring transaction',
|
||||
'stored_new_recurrence' => 'Recurring transaction ":title" stored successfully.',
|
||||
'edit_recurrence' => 'Edit recurring transaction ":title"',
|
||||
'recurring_repeats_until' => 'Repeats until :date',
|
||||
'recurring_repeats_forever' => 'Repeats forever',
|
||||
'recurring_repeats_x_times' => 'Repeats :count time(s)',
|
||||
'update_recurrence' => 'Update recurring transaction',
|
||||
'updated_recurrence' => 'Updated recurring transaction ":title"',
|
||||
'recurrence_is_inactive' => 'This recurring transaction is not active and will not generate new transactions.',
|
||||
];
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox"><label>
|
||||
{{ Form.checkbox('return_to_edit', '1', old('return_to_edit') == '1', {'id': name ~ '_return_to_edit'}) }}
|
||||
{{ Form.checkbox('return_to_edit', '1', null, {'id': name ~ '_return_to_edit'}) }}
|
||||
{{ trans('form.returnHereUpdateExplanation') }}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -222,7 +222,7 @@
|
||||
var transactionType = "{{ preFilled.transaction_type }}";
|
||||
var suggestUri = "{{ route('recurring.suggest') }}";
|
||||
var eventsUri = "{{ route('recurring.events') }}";
|
||||
var currentRepetitionType= "{{ currentRepetitionType }}";
|
||||
var currentRepetitionType = "{{ currentRepetitionType }}";
|
||||
</script>
|
||||
<script type="text/javascript" src="js/ff/recurring/edit.js?v={{ FF_VERSION }}"></script>
|
||||
{% endblock %}
|
||||
|
@ -54,12 +54,15 @@
|
||||
</div>
|
||||
</td>
|
||||
<td data-value="{{ rt.title }}">
|
||||
{% if rt.active == false %}<s>{% endif %}
|
||||
{{ rt.transaction_type|_ }}:
|
||||
|
||||
<a href="{{ route('recurring.show',rt.id) }}">{{ rt.title }}</a>
|
||||
{% if rt.active == false %}</s> ({{ 'inactive'|_|lower }}){% endif %}
|
||||
{% if rt.description|length > 0 %}
|
||||
<small><br>{{ rt.description }}</small>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</td>
|
||||
<td data-value="0">
|
||||
<ol>
|
||||
|
@ -12,10 +12,23 @@
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ array.title }}
|
||||
|
||||
({{ array.transaction_type }})
|
||||
|
||||
{% if array.active == false %}
|
||||
({{ 'inactive'|_|lower }})
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p><em>{{ array.description }}</em></p>
|
||||
|
||||
{% if array.active == false %}
|
||||
<p>
|
||||
{{ 'recurrence_is_inactive'|_ }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<ul>
|
||||
{% for rep in array.repetitions %}
|
||||
<li>{{ rep.description }}</li>
|
||||
@ -35,13 +48,13 @@
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ 'expected_transactions'|_ }}
|
||||
{{ ('expected_'~array.transaction_type~'s')|_ }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
|
||||
<ul>
|
||||
{% for rep in array.repetitions %}
|
||||
{% for rep in array.recurrence_repetitions %}
|
||||
<li>
|
||||
{{ rep.description }}
|
||||
{% if rep.repetition_skip == 1 %}
|
||||
@ -128,47 +141,47 @@
|
||||
|
||||
<!-- meta data -->
|
||||
{% if array.meta|length > 0 %}
|
||||
<div class="col-lg-4 col-md-12 col-sm-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ 'meta_data'|_ }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-hover sortable">
|
||||
<thead>
|
||||
<th style="width:30%;" data-defaultsign="az">{{ trans('list.field') }}</th>
|
||||
<th data-defaultsign="az">{{ trans('list.value') }}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for meta in array.meta %}
|
||||
<tr>
|
||||
<td>{{ trans('firefly.recurring_meta_field_'~meta.name) }}</td>
|
||||
<td>
|
||||
{% if meta.name == 'tags' %}
|
||||
{% for tag in meta.tags %}
|
||||
<span class="label label-info">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if meta.name == 'notes' %}
|
||||
{{ meta.value|markdown }}
|
||||
{% endif %}
|
||||
{% if meta.name == 'bill_id' %}
|
||||
<a href="{{ route('bills.show', [meta.bill_id]) }}">{{ meta.bill_name }}</a>
|
||||
{% endif %}
|
||||
{% if meta.name == 'piggy_bank_id' %}
|
||||
<a href="{{ route('piggy-banks.show', [meta.piggy_bank_id]) }}">{{ meta.piggy_bank_name }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<div class="col-lg-4 col-md-12 col-sm-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ 'meta_data'|_ }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-hover sortable">
|
||||
<thead>
|
||||
<th style="width:30%;" data-defaultsign="az">{{ trans('list.field') }}</th>
|
||||
<th data-defaultsign="az">{{ trans('list.value') }}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for meta in array.meta %}
|
||||
<tr>
|
||||
<td>{{ trans('firefly.recurring_meta_field_'~meta.name) }}</td>
|
||||
<td>
|
||||
{% if meta.name == 'tags' %}
|
||||
{% for tag in meta.tags %}
|
||||
<span class="label label-info">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if meta.name == 'notes' %}
|
||||
{{ meta.value|markdown }}
|
||||
{% endif %}
|
||||
{% if meta.name == 'bill_id' %}
|
||||
<a href="{{ route('bills.show', [meta.bill_id]) }}">{{ meta.bill_name }}</a>
|
||||
{% endif %}
|
||||
{% if meta.name == 'piggy_bank_id' %}
|
||||
<a href="{{ route('piggy-banks.show', [meta.piggy_bank_id]) }}">{{ meta.piggy_bank_name }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
@ -177,11 +190,11 @@
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
{{ 'transactions'|_ }}
|
||||
{{ ('created_'~array.transaction_type~'s')|_ }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
Bla bla
|
||||
List be here.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user