mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-19 19:01:39 +00:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
42458ce11d | ||
|
aceb683d07 | ||
|
b7517b49ed | ||
|
849b711b79 | ||
|
25585b28c7 | ||
|
073da8fb2a | ||
|
a787ff3f3c | ||
|
733b6d7eb7 | ||
|
36d8dee853 | ||
|
65a2e07d24 | ||
|
7c97c558ab | ||
|
a6bb61050c | ||
|
b184aa2315 | ||
|
e4595333e7 | ||
|
41dd139bde | ||
|
c577dd302a | ||
|
0ab87de78b | ||
|
8a22509b41 | ||
|
b024c18441 | ||
|
d9ac681a68 | ||
|
637a5579ec | ||
|
4794156e80 | ||
|
5f4db7874c | ||
|
b4ea1839a5 | ||
|
6a6d889983 | ||
|
287c2e7af8 | ||
|
0fe6acc8cf | ||
|
7d2dab7ca0 | ||
|
f68c1aff26 |
@@ -2,7 +2,7 @@
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M', 'custom'],
|
'index_periods' => ['1D', '1W', '1M', '3M', '6M','1Y', 'custom'],
|
||||||
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||||
'piggybank_periods' => ['day', 'week', 'month', 'year'],
|
'piggybank_periods' => ['day', 'week', 'month', 'year'],
|
||||||
'periods_to_text' => [
|
'periods_to_text' => [
|
||||||
@@ -21,6 +21,14 @@ return [
|
|||||||
'6M' => 'half year',
|
'6M' => 'half year',
|
||||||
'custom' => '(custom)'
|
'custom' => '(custom)'
|
||||||
],
|
],
|
||||||
|
'range_to_name' => [
|
||||||
|
'1D' => 'one day',
|
||||||
|
'1W' => 'one week',
|
||||||
|
'1M' => 'one month',
|
||||||
|
'3M' => 'three months',
|
||||||
|
'6M' => 'six months',
|
||||||
|
'1Y' => 'one year',
|
||||||
|
],
|
||||||
'range_to_repeat_freq' => [
|
'range_to_repeat_freq' => [
|
||||||
'1D' => 'weekly',
|
'1D' => 'weekly',
|
||||||
'1W' => 'weekly',
|
'1W' => 'weekly',
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Firefly\Exception\FireflyException;
|
||||||
use Firefly\Helper\Controllers\ChartInterface;
|
use Firefly\Helper\Controllers\ChartInterface;
|
||||||
use Firefly\Storage\Account\AccountRepositoryInterface;
|
use Firefly\Storage\Account\AccountRepositoryInterface;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ChartController
|
* Class ChartController
|
||||||
@@ -18,7 +20,7 @@ class ChartController extends BaseController
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ChartInterface $chart
|
* @param ChartInterface $chart
|
||||||
* @param AccountRepositoryInterface $accounts
|
* @param AccountRepositoryInterface $accounts
|
||||||
*/
|
*/
|
||||||
public function __construct(ChartInterface $chart, AccountRepositoryInterface $accounts)
|
public function __construct(ChartInterface $chart, AccountRepositoryInterface $accounts)
|
||||||
@@ -57,13 +59,13 @@ class ChartController extends BaseController
|
|||||||
|
|
||||||
$return = [
|
$return = [
|
||||||
'chart_title' => 'Overview for budget ' . $budget->name,
|
'chart_title' => 'Overview for budget ' . $budget->name,
|
||||||
'subtitle' => 'All envelopes',
|
'subtitle' => 'All envelopes',
|
||||||
'series' => [
|
'series' => [
|
||||||
[
|
[
|
||||||
'type' => 'line',
|
'type' => 'line',
|
||||||
'yAxis' => 1,
|
'yAxis' => 1,
|
||||||
'name' => 'Amount in envelope',
|
'name' => 'Amount in envelope',
|
||||||
'data' => $envelope
|
'data' => $envelope
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'type' => 'column',
|
'type' => 'column',
|
||||||
@@ -71,10 +73,10 @@ class ChartController extends BaseController
|
|||||||
'data' => $expense
|
'data' => $expense
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'type' => 'line',
|
'type' => 'line',
|
||||||
'yAxis' => 1,
|
'yAxis' => 1,
|
||||||
'name' => 'Spent percentage for envelope',
|
'name' => 'Spent percentage for envelope',
|
||||||
'data' => $left
|
'data' => $left
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -111,14 +113,14 @@ class ChartController extends BaseController
|
|||||||
|
|
||||||
$return = [
|
$return = [
|
||||||
'chart_title' => 'Overview for budget ' . $budget->name,
|
'chart_title' => 'Overview for budget ' . $budget->name,
|
||||||
'subtitle' =>
|
'subtitle' =>
|
||||||
'Between ' . $rep->startdate->format('M jS, Y') . ' and ' . $rep->enddate->format('M jS, Y'),
|
'Between ' . $rep->startdate->format('M jS, Y') . ' and ' . $rep->enddate->format('M jS, Y'),
|
||||||
'series' => [
|
'series' => [
|
||||||
[
|
[
|
||||||
'type' => 'column',
|
'type' => 'column',
|
||||||
'name' => 'Expenses per day',
|
'name' => 'Expenses per day',
|
||||||
'yAxis' => 1,
|
'yAxis' => 1,
|
||||||
'data' => $expense
|
'data' => $expense
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'type' => 'line',
|
'type' => 'line',
|
||||||
@@ -175,8 +177,8 @@ class ChartController extends BaseController
|
|||||||
}
|
}
|
||||||
$return = [
|
$return = [
|
||||||
'chart_title' => 'Overview for ' . $budget->name,
|
'chart_title' => 'Overview for ' . $budget->name,
|
||||||
'subtitle' => 'Not organized by an envelope',
|
'subtitle' => 'Not organized by an envelope',
|
||||||
'series' => [
|
'series' => [
|
||||||
[
|
[
|
||||||
'type' => 'column',
|
'type' => 'column',
|
||||||
'name' => 'Expenses per day',
|
'name' => 'Expenses per day',
|
||||||
@@ -245,11 +247,11 @@ class ChartController extends BaseController
|
|||||||
|
|
||||||
// create a serie for the repetition.
|
// create a serie for the repetition.
|
||||||
$currentSerie = [
|
$currentSerie = [
|
||||||
'type' => 'spline',
|
'type' => 'spline',
|
||||||
'id' => 'rep-' . $repetition->id,
|
'id' => 'rep-' . $repetition->id,
|
||||||
'yAxis' => 1,
|
'yAxis' => 1,
|
||||||
'name' => 'Envelope #' . $repetition->id . ' in ' . $repetition->periodShow(),
|
'name' => 'Envelope #' . $repetition->id . ' in ' . $repetition->periodShow(),
|
||||||
'data' => []
|
'data' => []
|
||||||
];
|
];
|
||||||
$current = clone $repetition->startdate;
|
$current = clone $repetition->startdate;
|
||||||
while ($current <= $repetition->enddate) {
|
while ($current <= $repetition->enddate) {
|
||||||
@@ -271,11 +273,11 @@ class ChartController extends BaseController
|
|||||||
|
|
||||||
$return = [
|
$return = [
|
||||||
'chart_title' => 'Overview for budget ' . $budget->name,
|
'chart_title' => 'Overview for budget ' . $budget->name,
|
||||||
'subtitle' =>
|
'subtitle' =>
|
||||||
'Between ' . Session::get('start')->format('M jS, Y') . ' and ' . Session::get('end')->format(
|
'Between ' . Session::get('start')->format('M jS, Y') . ' and ' . Session::get('end')->format(
|
||||||
'M jS, Y'
|
'M jS, Y'
|
||||||
),
|
),
|
||||||
'series' => $series
|
'series' => $series
|
||||||
];
|
];
|
||||||
|
|
||||||
return Response::json($return);
|
return Response::json($return);
|
||||||
@@ -296,8 +298,8 @@ class ChartController extends BaseController
|
|||||||
$serie = $this->_chart->categoryShowChart($category, $range, $start, $end);
|
$serie = $this->_chart->categoryShowChart($category, $range, $start, $end);
|
||||||
$data = [
|
$data = [
|
||||||
'chart_title' => $category->name,
|
'chart_title' => $category->name,
|
||||||
'subtitle' => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>',
|
'subtitle' => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>',
|
||||||
'series' => $serie
|
'series' => $serie
|
||||||
];
|
];
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -336,8 +338,8 @@ class ChartController extends BaseController
|
|||||||
'<a href="' . route('accounts.index') . '">View more</a>';
|
'<a href="' . route('accounts.index') . '">View more</a>';
|
||||||
$data = [
|
$data = [
|
||||||
'chart_title' => count($accounts) == 1 ? $accounts[0]->name : 'All accounts',
|
'chart_title' => count($accounts) == 1 ? $accounts[0]->name : 'All accounts',
|
||||||
'subtitle' => $url,
|
'subtitle' => $url,
|
||||||
'series' => []
|
'series' => []
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
@@ -431,11 +433,11 @@ class ChartController extends BaseController
|
|||||||
if ($limit > 0 || $expenses > 0) {
|
if ($limit > 0 || $expenses > 0) {
|
||||||
$data['labels'][] = $budget->name;
|
$data['labels'][] = $budget->name;
|
||||||
$data['series'][0]['data'][] = [
|
$data['series'][0]['data'][] = [
|
||||||
'y' => $limit,
|
'y' => $limit,
|
||||||
'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter
|
'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter
|
||||||
];
|
];
|
||||||
$data['series'][1]['data'][] = [
|
$data['series'][1]['data'][] = [
|
||||||
'y' => $expenses,
|
'y' => $expenses,
|
||||||
'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter
|
'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -444,26 +446,26 @@ class ChartController extends BaseController
|
|||||||
$set = \Auth::user()->transactionjournals()->whereNotIn(
|
$set = \Auth::user()->transactionjournals()->whereNotIn(
|
||||||
'transaction_journals.id', function ($query) use ($start, $end) {
|
'transaction_journals.id', function ($query) use ($start, $end) {
|
||||||
$query->select('transaction_journals.id')->from('transaction_journals')
|
$query->select('transaction_journals.id')->from('transaction_journals')
|
||||||
->leftJoin(
|
->leftJoin(
|
||||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
|
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
|
||||||
'transaction_journals.id'
|
'transaction_journals.id'
|
||||||
)
|
)
|
||||||
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
|
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
|
||||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
->where('components.class', 'Budget');
|
->where('components.class', 'Budget');
|
||||||
}
|
}
|
||||||
)->before($end)->after($start)->lessThan(0)->transactionTypes(['Withdrawal'])->sum('amount');
|
)->before($end)->after($start)->lessThan(0)->transactionTypes(['Withdrawal'])->sum('amount');
|
||||||
|
|
||||||
// This can be debugged by using get(['transaction_journals.*','transactions.amount']);
|
// This can be debugged by using get(['transaction_journals.*','transactions.amount']);
|
||||||
$data['labels'][] = 'No budget';
|
$data['labels'][] = 'No budget';
|
||||||
$data['series'][0]['data'][] = [
|
$data['series'][0]['data'][] = [
|
||||||
'y' => 0,
|
'y' => 0,
|
||||||
'url' => route('budgets.nobudget','session')
|
'url' => route('budgets.nobudget', 'session')
|
||||||
];
|
];
|
||||||
$data['series'][1]['data'][] = [
|
$data['series'][1]['data'][] = [
|
||||||
'y' => floatval($set) * -1,
|
'y' => floatval($set) * -1,
|
||||||
'url' => route('budgets.nobudget','session')
|
'url' => route('budgets.nobudget', 'session')
|
||||||
];
|
];
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -482,4 +484,120 @@ class ChartController extends BaseController
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks all recurring transactions, calculates the current "moment" and returns
|
||||||
|
* a list of yet to be paid (and paid) recurring transactions. This list can be used to show a beautiful chart
|
||||||
|
* to the end user who will love it and cherish it.
|
||||||
|
*
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function homeRecurring()
|
||||||
|
{
|
||||||
|
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
|
||||||
|
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set of paid transaction journals.
|
||||||
|
* Set of unpaid recurring transactions.
|
||||||
|
*/
|
||||||
|
$paid = [];
|
||||||
|
$unpaid = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop the recurring transactions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @var \RecurringTransaction $recurring */
|
||||||
|
foreach (\Auth::user()->recurringtransactions()->get() as $recurring) {
|
||||||
|
/*
|
||||||
|
* Start another loop starting at the $date.
|
||||||
|
*/
|
||||||
|
$start = clone $recurring->date;
|
||||||
|
$end = Carbon::now();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The jump we make depends on the $repeat_freq
|
||||||
|
*/
|
||||||
|
$current = clone $start;
|
||||||
|
|
||||||
|
while ($current <= $end) {
|
||||||
|
/*
|
||||||
|
* Get end of period for $current:
|
||||||
|
*/
|
||||||
|
$currentEnd = clone $current;
|
||||||
|
$toolkit->endOfPeriod($currentEnd, $recurring->repeat_freq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the current session range?
|
||||||
|
*/
|
||||||
|
if (\Session::get('end') >= $current and $currentEnd >= \Session::get('start')) {
|
||||||
|
/*
|
||||||
|
* Lets see if we've already spent money on this recurring transaction (it hath recurred).
|
||||||
|
*/
|
||||||
|
/** @var TransactionJournal $set */
|
||||||
|
$transaction = \Auth::user()->transactionjournals()->where('recurring_transaction_id', $recurring->id)->after($current)->before($currentEnd)->first();
|
||||||
|
|
||||||
|
if(is_null($transaction)) {
|
||||||
|
$unpaid[] = $recurring;
|
||||||
|
} else {
|
||||||
|
$paid[] = $transaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add some time for the next loop!
|
||||||
|
*/
|
||||||
|
$toolkit->addPeriod($current, $recurring->repeat_freq, intval($recurring->skip));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Get some colors going.
|
||||||
|
*/
|
||||||
|
$unPaidColours = $toolkit->colorRange('AA4643', 'FFFFFF', count($unpaid) == 0 ? 1 : count($unpaid));
|
||||||
|
$paidColours = $toolkit->colorRange('4572A7', 'FFFFFF', count($paid) == 0 ? 1 : count($paid));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The chart serie:
|
||||||
|
*/
|
||||||
|
$serie = [
|
||||||
|
'type' => 'pie',
|
||||||
|
'name' => 'Amount',
|
||||||
|
'data' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop paid and unpaid to make two haves for a pie chart.
|
||||||
|
*/
|
||||||
|
/** @var TransactionJournal $entry */
|
||||||
|
foreach ($paid as $index => $entry) {
|
||||||
|
$transactions = $entry->transactions()->get();
|
||||||
|
$amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount));
|
||||||
|
$serie['data'][] = [
|
||||||
|
'name' => 'Already paid "'.$entry->description.'"',
|
||||||
|
'y' => $amount,
|
||||||
|
'url' => route('transactions.show',$entry->id),
|
||||||
|
'objType' => 'paid',
|
||||||
|
'color' => $paidColours[$index]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @var RecurringTransaction $entry */
|
||||||
|
foreach ($unpaid as $index => $entry) {
|
||||||
|
$amount = (floatval($entry->amount_max) + floatval($entry->amount_min)) / 2;
|
||||||
|
$serie['data'][] = [
|
||||||
|
'name' => 'Still due: '.$entry->name,
|
||||||
|
'y' => $amount,
|
||||||
|
'url' => route('recurring.show',$entry->id),
|
||||||
|
'objType' => 'unpaid',
|
||||||
|
'color' => $unPaidColours[$index]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response::json([$serie]);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI;
|
use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI;
|
||||||
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
|
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
|
||||||
use Firefly\Storage\Reminder\ReminderRepositoryInterface as RRI;
|
|
||||||
use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI;
|
use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,24 +13,22 @@ class HomeController extends BaseController
|
|||||||
protected $_accounts;
|
protected $_accounts;
|
||||||
protected $_preferences;
|
protected $_preferences;
|
||||||
protected $_journal;
|
protected $_journal;
|
||||||
protected $_reminders;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ARI $accounts
|
* @param ARI $accounts
|
||||||
* @param PHI $preferences
|
* @param PHI $preferences
|
||||||
* @param TJRI $journal
|
* @param TJRI $journal
|
||||||
* @param RRI $reminders
|
|
||||||
*/
|
*/
|
||||||
public function __construct(ARI $accounts, PHI $preferences, TJRI $journal, RRI $reminders)
|
public function __construct(ARI $accounts, PHI $preferences, TJRI $journal)
|
||||||
{
|
{
|
||||||
$this->_accounts = $accounts;
|
$this->_accounts = $accounts;
|
||||||
$this->_preferences = $preferences;
|
$this->_preferences = $preferences;
|
||||||
$this->_journal = $journal;
|
$this->_journal = $journal;
|
||||||
$this->_reminders = $reminders;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jobDev() {
|
public function jobDev()
|
||||||
$fullName = storage_path().DIRECTORY_SEPARATOR.'firefly-export-2014-07-23.json';
|
{
|
||||||
|
$fullName = storage_path() . DIRECTORY_SEPARATOR . 'firefly-export-2014-07-23.json';
|
||||||
\Log::notice('Pushed start job.');
|
\Log::notice('Pushed start job.');
|
||||||
Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => 1]);
|
Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => 1]);
|
||||||
|
|
||||||
@@ -40,7 +37,8 @@ class HomeController extends BaseController
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function sessionPrev() {
|
public function sessionPrev()
|
||||||
|
{
|
||||||
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
|
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
|
||||||
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
||||||
$toolkit->prev();
|
$toolkit->prev();
|
||||||
@@ -51,7 +49,8 @@ class HomeController extends BaseController
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function sessionNext() {
|
public function sessionNext()
|
||||||
|
{
|
||||||
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
|
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
|
||||||
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
||||||
$toolkit->next();
|
$toolkit->next();
|
||||||
@@ -59,6 +58,18 @@ class HomeController extends BaseController
|
|||||||
//return Redirect::route('index');
|
//return Redirect::route('index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function rangeJump($range)
|
||||||
|
{
|
||||||
|
|
||||||
|
$valid = ['1D', '1W', '1M', '3M', '6M', '1Y',];
|
||||||
|
|
||||||
|
if (in_array($range, $valid)) {
|
||||||
|
$this->_preferences->set('viewRange', $range);
|
||||||
|
Session::forget('range');
|
||||||
|
}
|
||||||
|
return Redirect::back();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
@@ -102,6 +113,6 @@ class HomeController extends BaseController
|
|||||||
|
|
||||||
// build the home screen:
|
// build the home screen:
|
||||||
return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly')
|
return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly')
|
||||||
->with('subTitle', 'What\'s playing?')->with('mainTitleIcon','fa-fire');
|
->with('subTitle', 'What\'s playing?')->with('mainTitleIcon', 'fa-fire');
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -19,7 +19,6 @@ class JsonController extends BaseController
|
|||||||
$this->helper = $helper;
|
$this->helper = $helper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,11 +96,32 @@ class JsonController extends BaseController
|
|||||||
return Response::json($resultSet);
|
return Response::json($resultSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function recurringjournals(RecurringTransaction $recurringTransaction)
|
||||||
|
{
|
||||||
|
$parameters = $this->helper->dataTableParameters();
|
||||||
|
$parameters['transactionTypes'] = ['Withdrawal'];
|
||||||
|
$parameters['amount'] = 'negative';
|
||||||
|
|
||||||
|
$query = $this->helper->journalQuery($parameters);
|
||||||
|
|
||||||
|
$query->where('recurring_transaction_id', $recurringTransaction->id);
|
||||||
|
$resultSet = $this->helper->journalDataset($parameters, $query);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build return data:
|
||||||
|
*/
|
||||||
|
return Response::json($resultSet);
|
||||||
|
}
|
||||||
|
|
||||||
public function recurring()
|
public function recurring()
|
||||||
{
|
{
|
||||||
$parameters = $this->helper->dataTableParameters();
|
$parameters = $this->helper->dataTableParameters();
|
||||||
$query = $this->helper->recurringTransactionsQuery($parameters);
|
$query = $this->helper->recurringTransactionsQuery($parameters);
|
||||||
$resultSet = $this->helper->recurringTransactionsDataset($parameters, $query);
|
$resultSet = $this->helper->recurringTransactionsDataset($parameters, $query);
|
||||||
return Response::json($resultSet);
|
return Response::json($resultSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,9 +22,9 @@ class ProfileController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
View::share('title','Profile');
|
View::share('title', 'Profile');
|
||||||
View::share('subTitle',Auth::user()->email);
|
View::share('subTitle', Auth::user()->email);
|
||||||
View::share('mainTitleIcon','fa-user');
|
View::share('mainTitleIcon', 'fa-user');
|
||||||
return View::make('profile.index');
|
return View::make('profile.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +33,9 @@ class ProfileController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function changePassword()
|
public function changePassword()
|
||||||
{
|
{
|
||||||
View::share('title',Auth::user()->email);
|
View::share('title', Auth::user()->email);
|
||||||
View::share('subTitle','Change your password');
|
View::share('subTitle', 'Change your password');
|
||||||
View::share('mainTitleIcon','fa-user');
|
View::share('mainTitleIcon', 'fa-user');
|
||||||
return View::make('profile.change-password');
|
return View::make('profile.change-password');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@ class RecurringController extends BaseController
|
|||||||
public function __construct(RTR $repository, RI $helper)
|
public function __construct(RTR $repository, RI $helper)
|
||||||
{
|
{
|
||||||
$this->_repository = $repository;
|
$this->_repository = $repository;
|
||||||
$this->_helper = $helper;
|
$this->_helper = $helper;
|
||||||
|
|
||||||
View::share('title', 'Recurring transactions');
|
View::share('title', 'Recurring transactions');
|
||||||
View::share('mainTitleIcon', 'fa-rotate-right');
|
View::share('mainTitleIcon', 'fa-rotate-right');
|
||||||
@@ -102,6 +102,31 @@ class RecurringController extends BaseController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param RecurringTransaction $recurringTransaction
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function rescan(RecurringTransaction $recurringTransaction)
|
||||||
|
{
|
||||||
|
if (intval($recurringTransaction->active) == 0) {
|
||||||
|
Session::flash('warning', 'Inactive recurring transactions cannot be scanned.');
|
||||||
|
return Redirect::back();
|
||||||
|
}
|
||||||
|
// do something!
|
||||||
|
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $repo */
|
||||||
|
$repo = App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
|
||||||
|
$set = $repo->get();
|
||||||
|
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
foreach ($set as $journal) {
|
||||||
|
Event::fire('recurring.rescan', [$recurringTransaction, $journal]);
|
||||||
|
}
|
||||||
|
Session::flash('success', 'Rescanned everything.');
|
||||||
|
return Redirect::back();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
$data = Input::except(['_token', 'post_submit_action']);
|
$data = Input::except(['_token', 'post_submit_action']);
|
||||||
@@ -170,14 +195,14 @@ class RecurringController extends BaseController
|
|||||||
Session::flash('error', 'Could not update recurring transaction: ' . $messageBag->first());
|
Session::flash('error', 'Could not update recurring transaction: ' . $messageBag->first());
|
||||||
|
|
||||||
return Redirect::route('transactions.edit', $recurringTransaction->id)->withInput()
|
return Redirect::route('transactions.edit', $recurringTransaction->id)->withInput()
|
||||||
->withErrors($messageBag);
|
->withErrors($messageBag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'validate_only':
|
case 'validate_only':
|
||||||
$data = Input::all();
|
$data = Input::all();
|
||||||
$data['id'] = $recurringTransaction->id;
|
$data['id'] = $recurringTransaction->id;
|
||||||
$messageBags = $this->_helper->validate($data);
|
$messageBags = $this->_helper->validate($data);
|
||||||
|
|
||||||
Session::flash('warnings', $messageBags['warnings']);
|
Session::flash('warnings', $messageBags['warnings']);
|
||||||
|
@@ -1,97 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Firefly\Storage\Reminder\ReminderRepositoryInterface as RRI;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ReminderController
|
* Class ReminderController
|
||||||
*
|
*
|
||||||
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
|
|
||||||
*/
|
*/
|
||||||
class ReminderController extends BaseController
|
class ReminderController extends BaseController
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $_repository;
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param RRI $repository
|
|
||||||
*/
|
|
||||||
public function __construct(RRI $repository)
|
|
||||||
{
|
|
||||||
$this->_repository = $repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Reminder $reminder
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function dismiss(\Reminder $reminder)
|
|
||||||
{
|
|
||||||
$reminder = $this->_repository->deactivate($reminder);
|
|
||||||
|
|
||||||
return Response::json($reminder->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the reminders currently active for the modal dialog.
|
|
||||||
*/
|
|
||||||
public function modalDialog()
|
|
||||||
{
|
|
||||||
$today = new Carbon;
|
|
||||||
$reminders = $this->_repository->getPiggybankReminders();
|
|
||||||
|
|
||||||
/** @var \Reminder $reminder */
|
|
||||||
foreach ($reminders as $index => $reminder) {
|
|
||||||
if (\Session::has('dismissal-' . $reminder->id)) {
|
|
||||||
$time = \Session::get('dismissal-' . $reminder->id);
|
|
||||||
if ($time >= $today) {
|
|
||||||
unset($reminders[$index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return View::make('reminders.popup')->with('reminders', $reminders);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Reminder $reminder
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function postpone(\Reminder $reminder)
|
|
||||||
{
|
|
||||||
$now = new Carbon;
|
|
||||||
$now->addDay();
|
|
||||||
Session::put('dismissal-' . $reminder->id, $now);
|
|
||||||
|
|
||||||
return Response::json($reminder->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Reminder $reminder
|
|
||||||
*
|
|
||||||
* @return $this|\Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function redirect(\Reminder $reminder)
|
|
||||||
{
|
|
||||||
if ($reminder instanceof PiggybankReminder) {
|
|
||||||
// fields to prefill:
|
|
||||||
$parameters = [
|
|
||||||
'account_to_id' => $reminder->piggybank->account->id,
|
|
||||||
'amount' => round($reminder->amountToSave(), 2),
|
|
||||||
'description' => 'Money for ' . $reminder->piggybank->name,
|
|
||||||
'piggybank_id' => $reminder->piggybank->id,
|
|
||||||
'reminder_id' => $reminder->id
|
|
||||||
];
|
|
||||||
|
|
||||||
return Redirect::to(
|
|
||||||
route('transactions.create', ['what' => 'transfer']) . '?' . http_build_query($parameters)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return View::make('error')->with('message', 'No such reminder.');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -27,26 +27,11 @@ class CreateRemindersTable extends Migration
|
|||||||
'reminders', function (Blueprint $table) {
|
'reminders', function (Blueprint $table) {
|
||||||
$table->increments('id');
|
$table->increments('id');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
$table->string('class', 40);
|
|
||||||
$table->integer('piggybank_id')->unsigned()->nullable();
|
|
||||||
$table->integer('recurring_transaction_id')->unsigned()->nullable();
|
|
||||||
$table->integer('user_id')->unsigned();
|
$table->integer('user_id')->unsigned();
|
||||||
$table->date('startdate');
|
$table->date('startdate');
|
||||||
$table->date('enddate')->nullable();
|
$table->date('enddate')->nullable();
|
||||||
$table->boolean('active');
|
$table->boolean('active');
|
||||||
|
|
||||||
|
|
||||||
// connect reminders to piggy banks.
|
|
||||||
$table->foreign('piggybank_id')
|
|
||||||
->references('id')->on('piggybanks')
|
|
||||||
->onDelete('set null');
|
|
||||||
|
|
||||||
// connect reminders to recurring transactions.
|
|
||||||
$table->foreign('recurring_transaction_id')
|
|
||||||
->references('id')->on('recurring_transactions')
|
|
||||||
->onDelete('set null');
|
|
||||||
|
|
||||||
|
|
||||||
// connect reminders to users
|
// connect reminders to users
|
||||||
$table->foreign('user_id')
|
$table->foreign('user_id')
|
||||||
->references('id')->on('users')
|
->references('id')->on('users')
|
||||||
|
@@ -10,6 +10,7 @@ App::before(
|
|||||||
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
|
||||||
$toolkit->getDateRange();
|
$toolkit->getDateRange();
|
||||||
$toolkit->checkImportJobs();
|
$toolkit->checkImportJobs();
|
||||||
|
Event::fire('recurring.verify');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -355,7 +355,7 @@ class Json implements JsonInterface
|
|||||||
* Loop set and create entries to return.
|
* Loop set and create entries to return.
|
||||||
*/
|
*/
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$data['data'][] = [
|
$set = [
|
||||||
|
|
||||||
'name' => ['name' => $entry->name, 'url' => route('recurring.show', $entry->id)],
|
'name' => ['name' => $entry->name, 'url' => route('recurring.show', $entry->id)],
|
||||||
'match' => explode(' ', $entry->match),
|
'match' => explode(' ', $entry->match),
|
||||||
@@ -370,6 +370,11 @@ class Json implements JsonInterface
|
|||||||
'delete' => route('recurring.delete', $entry->id)
|
'delete' => route('recurring.delete', $entry->id)
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if (intval($entry->skip) > 0) {
|
||||||
|
$set['repeat_freq'] = $entry->repeat_freq . ' (skip ' . $entry->skip . ')';
|
||||||
|
}
|
||||||
|
$data['data'][] = $set;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
|
@@ -84,22 +84,23 @@ class Toolkit implements ToolkitInterface
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function checkImportJobs() {
|
public function checkImportJobs()
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Get all jobs.
|
* Get all jobs.
|
||||||
*/
|
*/
|
||||||
/** @var \Importmap $importJob */
|
/** @var \Importmap $importJob */
|
||||||
$importJob = \Importmap::where('user_id',\Auth::user()->id)
|
$importJob = \Importmap::where('user_id', \Auth::user()->id)
|
||||||
->where('totaljobs','>',\DB::Raw('`jobsdone`'))
|
->where('totaljobs', '>', \DB::Raw('`jobsdone`'))
|
||||||
->orderBy('created_at','DESC')
|
->orderBy('created_at', 'DESC')
|
||||||
->first();
|
->first();
|
||||||
if(!is_null($importJob)) {
|
if (!is_null($importJob)) {
|
||||||
$diff = intval($importJob->totaljobs) - intval($importJob->jobsdone);
|
$diff = intval($importJob->totaljobs) - intval($importJob->jobsdone);
|
||||||
$date = new Carbon;
|
$date = new Carbon;
|
||||||
$today = new Carbon;
|
$today = new Carbon;
|
||||||
$date->addSeconds($diff);
|
$date->addSeconds($diff);
|
||||||
\Session::put('job_pct',$importJob->pct());
|
\Session::put('job_pct', $importJob->pct());
|
||||||
\Session::put('job_text',$date->diffForHumans());
|
\Session::put('job_text', $date->diffForHumans());
|
||||||
} else {
|
} else {
|
||||||
\Session::forget('job_pct');
|
\Session::forget('job_pct');
|
||||||
\Session::forget('job_text');
|
\Session::forget('job_text');
|
||||||
@@ -134,7 +135,6 @@ class Toolkit implements ToolkitInterface
|
|||||||
*/
|
*/
|
||||||
protected function _updateStartDate($range, Carbon $start)
|
protected function _updateStartDate($range, Carbon $start)
|
||||||
{
|
{
|
||||||
$today = new Carbon;
|
|
||||||
switch ($range) {
|
switch ($range) {
|
||||||
case '1D':
|
case '1D':
|
||||||
$start->startOfDay();
|
$start->startOfDay();
|
||||||
@@ -149,12 +149,15 @@ class Toolkit implements ToolkitInterface
|
|||||||
$start->firstOfQuarter();
|
$start->firstOfQuarter();
|
||||||
break;
|
break;
|
||||||
case '6M':
|
case '6M':
|
||||||
if (intval($today->format('m')) >= 7) {
|
if (intval($start->format('m')) >= 7) {
|
||||||
$start->startOfYear()->addMonths(6);
|
$start->startOfYear()->addMonths(6);
|
||||||
} else {
|
} else {
|
||||||
$start->startOfYear();
|
$start->startOfYear();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '1Y':
|
||||||
|
$start->startOfYear();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $start;
|
return $start;
|
||||||
@@ -170,34 +173,34 @@ class Toolkit implements ToolkitInterface
|
|||||||
*/
|
*/
|
||||||
protected function _updateEndDate($range, Carbon $start)
|
protected function _updateEndDate($range, Carbon $start)
|
||||||
{
|
{
|
||||||
|
$end = clone $start;
|
||||||
switch ($range) {
|
switch ($range) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('_updateEndDate cannot handle $range ' . $range);
|
||||||
|
break;
|
||||||
case '1D':
|
case '1D':
|
||||||
$end = clone $start;
|
|
||||||
$end->endOfDay();
|
$end->endOfDay();
|
||||||
break;
|
break;
|
||||||
case '1W':
|
case '1W':
|
||||||
$end = clone $start;
|
|
||||||
$end->endOfWeek();
|
$end->endOfWeek();
|
||||||
break;
|
break;
|
||||||
case '1M':
|
case '1M':
|
||||||
$end = clone $start;
|
|
||||||
$end->endOfMonth();
|
$end->endOfMonth();
|
||||||
break;
|
break;
|
||||||
case '3M':
|
case '3M':
|
||||||
$end = clone $start;
|
|
||||||
$end->lastOfQuarter();
|
$end->lastOfQuarter();
|
||||||
break;
|
break;
|
||||||
case '6M':
|
case '6M':
|
||||||
$end = clone $start;
|
|
||||||
if (intval($start->format('m')) >= 7) {
|
if (intval($start->format('m')) >= 7) {
|
||||||
$end->endOfYear();
|
$end->endOfYear();
|
||||||
} else {
|
} else {
|
||||||
$end->startOfYear()->addMonths(6);
|
$end->startOfYear()->addMonths(6);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
case '1Y':
|
||||||
throw new FireflyException('Nothing happened with $end!');
|
$end->endOfYear();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $end;
|
return $end;
|
||||||
@@ -209,15 +212,39 @@ class Toolkit implements ToolkitInterface
|
|||||||
default:
|
default:
|
||||||
throw new FireflyException('No _periodName() for range "' . $range . '"');
|
throw new FireflyException('No _periodName() for range "' . $range . '"');
|
||||||
break;
|
break;
|
||||||
|
case '1D':
|
||||||
|
return $date->format('jS F Y');
|
||||||
|
break;
|
||||||
|
case '1W':
|
||||||
|
return 'week ' . $date->format('W, Y');
|
||||||
|
break;
|
||||||
case '1M':
|
case '1M':
|
||||||
return $date->format('F Y');
|
return $date->format('F Y');
|
||||||
break;
|
break;
|
||||||
|
case '3M':
|
||||||
|
$month = intval($date->format('m'));
|
||||||
|
return 'Q' . ceil(($month / 12) * 4) . ' ' . $date->format('Y');
|
||||||
|
break;
|
||||||
|
case '6M':
|
||||||
|
$month = intval($date->format('m'));
|
||||||
|
$half = ceil(($month / 12) * 2);
|
||||||
|
$halfName = $half == 1 ? 'first' : 'second';
|
||||||
|
return $halfName . ' half of ' . $date->format('d-m-Y');
|
||||||
|
break;
|
||||||
|
case '1Y':
|
||||||
|
return $date->format('Y');
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _previous($range, Carbon $date)
|
protected function _previous($range, Carbon $date)
|
||||||
{
|
{
|
||||||
switch ($range) {
|
switch ($range) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot do _previous() on ' . $range);
|
||||||
|
break;
|
||||||
case '1D':
|
case '1D':
|
||||||
$date->startOfDay()->subDay();
|
$date->startOfDay()->subDay();
|
||||||
break;
|
break;
|
||||||
@@ -231,12 +258,17 @@ class Toolkit implements ToolkitInterface
|
|||||||
$date->firstOfQuarter()->subMonths(3)->firstOfQuarter();
|
$date->firstOfQuarter()->subMonths(3)->firstOfQuarter();
|
||||||
break;
|
break;
|
||||||
case '6M':
|
case '6M':
|
||||||
if (intval($date->format('m')) >= 7) {
|
$month = intval($date->format('m'));
|
||||||
$date->startOfYear();
|
if ($month <= 6) {
|
||||||
} else {
|
|
||||||
$date->startOfYear()->subMonths(6);
|
$date->startOfYear()->subMonths(6);
|
||||||
|
} else {
|
||||||
|
$date->startOfYear();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '1Y':
|
||||||
|
$date->startOfYear()->subYear();
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return $date;
|
return $date;
|
||||||
}
|
}
|
||||||
@@ -254,7 +286,7 @@ class Toolkit implements ToolkitInterface
|
|||||||
$date->endOfMonth()->addDay()->startOfMonth();
|
$date->endOfMonth()->addDay()->startOfMonth();
|
||||||
break;
|
break;
|
||||||
case '3M':
|
case '3M':
|
||||||
$date->lastOfQuarter();
|
$date->lastOfQuarter()->addDay();
|
||||||
break;
|
break;
|
||||||
case '6M':
|
case '6M':
|
||||||
if (intval($date->format('m')) >= 7) {
|
if (intval($date->format('m')) >= 7) {
|
||||||
@@ -263,6 +295,12 @@ class Toolkit implements ToolkitInterface
|
|||||||
$date->startOfYear()->addMonths(6);
|
$date->startOfYear()->addMonths(6);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '1Y':
|
||||||
|
$date->startOfYear()->addYear();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot do _next() on ' . $range);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return $date;
|
return $date;
|
||||||
}
|
}
|
||||||
@@ -311,7 +349,7 @@ class Toolkit implements ToolkitInterface
|
|||||||
* Takes any collection and tries to make a sensible select list compatible array of it.
|
* Takes any collection and tries to make a sensible select list compatible array of it.
|
||||||
*
|
*
|
||||||
* @param Collection $set
|
* @param Collection $set
|
||||||
* @param null $titleField
|
* @param null $titleField
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
@@ -343,4 +381,127 @@ class Toolkit implements ToolkitInterface
|
|||||||
}
|
}
|
||||||
return $selectList;
|
return $selectList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $start
|
||||||
|
* @param string $end
|
||||||
|
* @param int $steps
|
||||||
|
*/
|
||||||
|
public function colorRange($start, $end, $steps = 5)
|
||||||
|
{
|
||||||
|
if (strlen($start) != 6) {
|
||||||
|
throw new FireflyException('Start, ' . e($start) . ' should be a six character HTML colour.');
|
||||||
|
}
|
||||||
|
if (strlen($end) != 6) {
|
||||||
|
throw new FireflyException('End, ' . e($end) . ' should be a six character HTML colour.');
|
||||||
|
}
|
||||||
|
if ($steps < 1) {
|
||||||
|
throw new FireflyException('Steps must be > 1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = '#' . $start;
|
||||||
|
$end = '#' . $end;
|
||||||
|
/*
|
||||||
|
* Split html colours.
|
||||||
|
*/
|
||||||
|
list($rs, $gs, $bs) = sscanf($start, "#%02x%02x%02x");
|
||||||
|
list($re, $ge, $be) = sscanf($end, "#%02x%02x%02x");
|
||||||
|
|
||||||
|
$stepr = ($re - $rs) / $steps;
|
||||||
|
$stepg = ($ge - $gs) / $steps;
|
||||||
|
$stepb = ($be - $bs) / $steps;
|
||||||
|
|
||||||
|
$return = [];
|
||||||
|
for ($i = 0; $i <= $steps; $i++) {
|
||||||
|
$cr = $rs + ($stepr * $i);
|
||||||
|
$cg = $gs + ($stepg * $i);
|
||||||
|
$cb = $bs + ($stepb * $i);
|
||||||
|
|
||||||
|
$return[] = $this->rgb2html($cr, $cg, $cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function rgb2html($r, $g = -1, $b = -1)
|
||||||
|
{
|
||||||
|
$r = dechex($r < 0 ? 0 : ($r > 255 ? 255 : $r));
|
||||||
|
$g = dechex($g < 0 ? 0 : ($g > 255 ? 255 : $g));
|
||||||
|
$b = dechex($b < 0 ? 0 : ($b > 255 ? 255 : $b));
|
||||||
|
|
||||||
|
$color = (strlen($r) < 2 ? '0' : '') . $r;
|
||||||
|
$color .= (strlen($g) < 2 ? '0' : '') . $g;
|
||||||
|
$color .= (strlen($b) < 2 ? '0' : '') . $b;
|
||||||
|
return '#' . $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $currentEnd
|
||||||
|
* @param $repeatFreq
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function endOfPeriod(Carbon $currentEnd, $repeatFreq)
|
||||||
|
{
|
||||||
|
switch ($repeatFreq) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot do getFunctionForRepeatFreq for $repeat_freq ' . $repeatFreq);
|
||||||
|
break;
|
||||||
|
case 'daily':
|
||||||
|
$currentEnd->addDay();
|
||||||
|
break;
|
||||||
|
case 'weekly':
|
||||||
|
$currentEnd->addWeek()->subDay();
|
||||||
|
break;
|
||||||
|
case 'monthly':
|
||||||
|
$currentEnd->addMonth()->subDay();
|
||||||
|
break;
|
||||||
|
case 'quarterly':
|
||||||
|
$currentEnd->addMonths(3)->subDay();
|
||||||
|
break;
|
||||||
|
case 'half-year':
|
||||||
|
$currentEnd->addMonths(6)->subDay();
|
||||||
|
break;
|
||||||
|
case 'yearly':
|
||||||
|
$currentEnd->addYear()->subDay();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
* @param $repeatFreq
|
||||||
|
* @param $skip
|
||||||
|
* @return Carbon
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function addPeriod(Carbon $date, $repeatFreq, $skip)
|
||||||
|
{
|
||||||
|
$add = ($skip + 1);
|
||||||
|
switch ($repeatFreq) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot do getFunctionForRepeatFreq for $repeat_freq ' . $repeatFreq);
|
||||||
|
break;
|
||||||
|
case 'daily':
|
||||||
|
$date->addDays($add);
|
||||||
|
break;
|
||||||
|
case 'weekly':
|
||||||
|
$date->addWeeks($add);
|
||||||
|
break;
|
||||||
|
case 'monthly':
|
||||||
|
$date->addMonths($add);
|
||||||
|
break;
|
||||||
|
case 'quarterly':
|
||||||
|
$months = $add * 3;
|
||||||
|
$date->addMonths($months);
|
||||||
|
break;
|
||||||
|
case 'half-year':
|
||||||
|
$months = $add * 6;
|
||||||
|
$date->addMonths($months);
|
||||||
|
break;
|
||||||
|
case 'yearly':
|
||||||
|
$date->addYears($add);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Firefly\Helper\Toolkit;
|
namespace Firefly\Helper\Toolkit;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +22,7 @@ interface ToolkitInterface
|
|||||||
* Takes any collection and tries to make a sensible select list compatible array of it.
|
* Takes any collection and tries to make a sensible select list compatible array of it.
|
||||||
*
|
*
|
||||||
* @param Collection $set
|
* @param Collection $set
|
||||||
* @param null $titleField
|
* @param null $titleField
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
@@ -33,4 +34,19 @@ interface ToolkitInterface
|
|||||||
|
|
||||||
public function checkImportJobs();
|
public function checkImportJobs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $start
|
||||||
|
* @param string $end
|
||||||
|
* @param int $steps
|
||||||
|
*/
|
||||||
|
public function colorRange($start, $end, $steps = 5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
* @param $repeatFreq
|
||||||
|
* @param $skip
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function addPeriod(Carbon $date, $repeatFreq, $skip);
|
||||||
|
|
||||||
}
|
}
|
@@ -175,12 +175,6 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
|
|||||||
return $messageBag;
|
return $messageBag;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($recurringTransaction->date < Carbon::now()) {
|
|
||||||
$messageBag->add('date', 'Must be in the future.');
|
|
||||||
return $messageBag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($recurringTransaction->validate()) {
|
if ($recurringTransaction->validate()) {
|
||||||
$recurringTransaction->save();
|
$recurringTransaction->save();
|
||||||
} else {
|
} else {
|
||||||
|
@@ -31,17 +31,4 @@ class EloquentReminderRepository implements ReminderRepositoryInterface
|
|||||||
{
|
{
|
||||||
$this->_user = \Auth::user();
|
$this->_user = \Auth::user();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \Reminder $reminder
|
|
||||||
*
|
|
||||||
* @return mixed|void
|
|
||||||
*/
|
|
||||||
public function deactivate(\Reminder $reminder)
|
|
||||||
{
|
|
||||||
$reminder->active = 0;
|
|
||||||
$reminder->save();
|
|
||||||
|
|
||||||
return $reminder;
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -10,14 +10,6 @@ namespace Firefly\Storage\Reminder;
|
|||||||
interface ReminderRepositoryInterface
|
interface ReminderRepositoryInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \Reminder $reminder
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function deactivate(\Reminder $reminder);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \User $user
|
* @param \User $user
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
@@ -5,6 +5,7 @@ namespace Firefly\Storage\TransactionJournal;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Queue\Jobs\Job;
|
use Illuminate\Queue\Jobs\Job;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\MessageBag;
|
use Illuminate\Support\MessageBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,6 +25,15 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
|
|||||||
$this->_user = \Auth::user();
|
$this->_user = \Auth::user();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get them ALL
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function get() {
|
||||||
|
return $this->_user->transactionjournals()->with('transactions')->get();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Job $job
|
* @param Job $job
|
||||||
* @param array $payload
|
* @param array $payload
|
||||||
|
@@ -4,6 +4,7 @@ namespace Firefly\Storage\TransactionJournal;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Queue\Jobs\Job;
|
use Illuminate\Queue\Jobs\Job;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface TransactionJournalRepositoryInterface
|
* Interface TransactionJournalRepositoryInterface
|
||||||
@@ -20,6 +21,13 @@ interface TransactionJournalRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function importTransaction(Job $job, array $payload);
|
public function importTransaction(Job $job, array $payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get them ALL
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function get();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Job $job
|
* @param Job $job
|
||||||
* @param array $payload
|
* @param array $payload
|
||||||
|
@@ -23,44 +23,19 @@ class EloquentJournalTrigger
|
|||||||
/*
|
/*
|
||||||
* Grab all recurring events.
|
* Grab all recurring events.
|
||||||
*/
|
*/
|
||||||
$set = $journal->user()->first()->recurringtransactions()->get();
|
$set = $journal->user()->first()->recurringtransactions()->get();
|
||||||
$result = [];
|
$result = [];
|
||||||
/*
|
/*
|
||||||
* Prep vars
|
* Prep vars
|
||||||
*/
|
*/
|
||||||
$description = strtolower($journal->description);
|
$description = strtolower($journal->description);
|
||||||
|
$result = [0 => 0];
|
||||||
|
|
||||||
/** @var \RecurringTransaction $recurring */
|
/** @var \RecurringTransaction $recurring */
|
||||||
foreach ($set as $recurring) {
|
foreach ($set as $recurring) {
|
||||||
$matches = explode(' ', $recurring->match);
|
\Event::fire('recurring.rescan', [$recurring, $journal]);
|
||||||
|
|
||||||
/*
|
|
||||||
* Count the number of matches.
|
|
||||||
*/
|
|
||||||
$count = 0;
|
|
||||||
foreach ($matches as $word) {
|
|
||||||
if (!(strpos($description, $word) === false)) {
|
|
||||||
$count++;
|
|
||||||
\Log::debug('Recurring transaction #' . $recurring->id . ': word "' . $word . '" found in "' . $description . '".');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$result[$recurring->id] = $count;
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* The one with the highest value is the winrar!
|
|
||||||
*/
|
|
||||||
$index = array_search(max($result), $result);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find the recurring transaction:
|
|
||||||
*/
|
|
||||||
if (count($result[$index]) > 0) {
|
|
||||||
$winner = $journal->user()->first()->recurringtransactions()->find($index);
|
|
||||||
if ($winner) {
|
|
||||||
$journal->recurringTransaction()->associate($winner);
|
|
||||||
$journal->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -107,159 +107,6 @@ class EloquentPiggybankTrigger
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whenever a repetition is made, the decision is there to make reminders for it. Or not.
|
|
||||||
* Some combinations are "invalid" or impossible and will never trigger reminders. Others do.
|
|
||||||
*
|
|
||||||
* The numbers below refer to a small list I made in a text-file (it no longer exists) which contained the eight
|
|
||||||
* binary combinations that can be made of three properties each piggy bank has (among others):
|
|
||||||
*
|
|
||||||
* - Whether or not it has a start date.
|
|
||||||
* - Whether or not it has an end date.
|
|
||||||
* - Whether or not the piggy bank repeats itself.
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
* @SuppressWarnings(PHPMD.NPathComplexity)
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*
|
|
||||||
* @param \PiggybankRepetition $repetition
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
public function createdRepetition(\PiggybankRepetition $repetition)
|
|
||||||
{
|
|
||||||
\Log::debug('TRIGGER on createdRepetition() for repetition #' . $repetition->id);
|
|
||||||
|
|
||||||
$piggyBank = $repetition->piggybank;
|
|
||||||
|
|
||||||
// first, exclude all combinations that will not generate (valid) reminders
|
|
||||||
|
|
||||||
// no reminders needed (duh)
|
|
||||||
if (is_null(($piggyBank->reminder))) {
|
|
||||||
\Log::debug('No reminders because no reminder needed.');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no start, no target, no repeat (#1):
|
|
||||||
if (is_null($piggyBank->startdate) && is_null($piggyBank->targetdate) && $piggyBank->repeats == 0) {
|
|
||||||
\Log::debug('No reminders because no start, no target, no repeat (#1)');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no start, but repeats (#5):
|
|
||||||
if (is_null($piggyBank->startdate) && $piggyBank->repeats == 1) {
|
|
||||||
\Log::debug('No reminders because no start, but repeats (#5)');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no start, no end, but repeats (#6)
|
|
||||||
if (is_null($piggyBank->startdate) && is_null($piggyBank->targetdate) && $piggyBank->repeats == 1) {
|
|
||||||
\Log::debug('No reminders because no start, no end, but repeats (#6)');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no end, but repeats (#7)
|
|
||||||
if (is_null($piggyBank->targetdate) && $piggyBank->repeats == 1) {
|
|
||||||
\Log::debug('No reminders because no end, but repeats (#7)');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
\Log::debug('Will continue...');
|
|
||||||
/*
|
|
||||||
* #2, #3, #4 and #8 are valid combo's.
|
|
||||||
*
|
|
||||||
* We add two years to the end when the repetition has no target date; we "pretend" there is a target date.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (is_null($repetition->targetdate)) {
|
|
||||||
$end = new Carbon;
|
|
||||||
$end->addYears(2);
|
|
||||||
} else {
|
|
||||||
$end = $repetition->targetdate;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* If there is no start date, the start dat becomes right now.
|
|
||||||
*/
|
|
||||||
if (is_null($repetition->startdate)) {
|
|
||||||
$start = new Carbon;
|
|
||||||
} else {
|
|
||||||
$start = $repetition->startdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Firefly checks every period X between $start and $end and if necessary creates a reminder. Firefly
|
|
||||||
* only creates reminders if the $current date is after today. Piggy banks may have their start in the past.
|
|
||||||
*
|
|
||||||
* This loop will jump a month when the reminder is set monthly, a week when it's set weekly, etcetera.
|
|
||||||
*/
|
|
||||||
$current = $start;
|
|
||||||
$today = new Carbon;
|
|
||||||
$today->startOfDay();
|
|
||||||
while ($current <= $end) {
|
|
||||||
\Log::debug('Looping reminder dates; now at ' . $current);
|
|
||||||
/*
|
|
||||||
* Piggy bank reminders start X days before the actual date of the event.
|
|
||||||
*/
|
|
||||||
$reminderStart = clone $current;
|
|
||||||
switch ($piggyBank->reminder) {
|
|
||||||
case 'day':
|
|
||||||
$reminderStart->subDay();
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
$reminderStart->subDays(4);
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
$reminderStart->subDays(21);
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
$reminderStart->subMonths(9);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the date is past today we create a reminder, otherwise we don't. The end date is the date
|
|
||||||
* the reminder is due; after that it is invalid.
|
|
||||||
*/
|
|
||||||
if ($current >= $today) {
|
|
||||||
$reminder = new \PiggybankReminder;
|
|
||||||
$reminder->piggybank()->associate($piggyBank);
|
|
||||||
$reminder->user()->associate(\Auth::user());
|
|
||||||
$reminder->startdate = $reminderStart;
|
|
||||||
$reminder->enddate = $current;
|
|
||||||
$reminder->active = 1;
|
|
||||||
\Log::debug('Will create a reminder. Is it valid?');
|
|
||||||
\Log::debug($reminder->validate());
|
|
||||||
try {
|
|
||||||
|
|
||||||
$reminder->save();
|
|
||||||
} catch (QueryException $e) {
|
|
||||||
\Log::error('Could not save reminder: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
\Log::debug('Current is before today, will not make a reminder.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Here Firefly jumps ahead to the next reminder period.
|
|
||||||
*/
|
|
||||||
switch ($piggyBank->reminder) {
|
|
||||||
case 'day':
|
|
||||||
$current->addDays($piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
$current->addWeeks($piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
$current->addMonths($piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
$current->addYears($piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Piggybank $piggyBank
|
* @param \Piggybank $piggyBank
|
||||||
*
|
*
|
||||||
@@ -267,13 +114,6 @@ class EloquentPiggybankTrigger
|
|||||||
*/
|
*/
|
||||||
public function destroy(\Piggybank $piggyBank)
|
public function destroy(\Piggybank $piggyBank)
|
||||||
{
|
{
|
||||||
$reminders = $piggyBank->piggybankreminders()->get();
|
|
||||||
/** @var \PiggybankReminder $reminder */
|
|
||||||
foreach ($reminders as $reminder) {
|
|
||||||
$reminder->delete();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,9 +196,6 @@ class EloquentPiggybankTrigger
|
|||||||
'piggybanks.check', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@checkRepeatingPiggies'
|
'piggybanks.check', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@checkRepeatingPiggies'
|
||||||
);
|
);
|
||||||
|
|
||||||
$events->listen(
|
|
||||||
'piggybanks.repetition', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@createdRepetition'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace Firefly\Trigger\Recurring;
|
namespace Firefly\Trigger\Recurring;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Firefly\Exception\FireflyException;
|
||||||
use Illuminate\Events\Dispatcher;
|
use Illuminate\Events\Dispatcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,8 +29,67 @@ class EloquentRecurringTrigger
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createReminders()
|
/**
|
||||||
|
* @param \RecurringTransaction $recurring
|
||||||
|
* @param \TransactionJournal $journal
|
||||||
|
*/
|
||||||
|
public function rescan(\RecurringTransaction $recurring, \TransactionJournal $journal)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Match words.
|
||||||
|
*/
|
||||||
|
$wordMatch = false;
|
||||||
|
$matches = explode(' ', $recurring->match);
|
||||||
|
$description = strtolower($journal->description);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attach expense account to description for more narrow matching.
|
||||||
|
*/
|
||||||
|
$transactions = $journal->transactions()->get();
|
||||||
|
/** @var \Transaction $transaction */
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
/** @var \Account $account */
|
||||||
|
$account = $transaction->account()->first();
|
||||||
|
/** @var \AccountType $type */
|
||||||
|
$type = $account->accountType()->first();
|
||||||
|
if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') {
|
||||||
|
$description .= ' ' . strtolower($account->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
foreach ($matches as $word) {
|
||||||
|
if (!(strpos($description, strtolower($word)) === false)) {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($count >= count($matches)) {
|
||||||
|
$wordMatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match amount.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$amountMatch = false;
|
||||||
|
if (count($transactions) > 1) {
|
||||||
|
|
||||||
|
$amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount));
|
||||||
|
$min = floatval($recurring->amount_min);
|
||||||
|
$max = floatval($recurring->amount_max);
|
||||||
|
if ($amount >= $min && $amount <= $max) {
|
||||||
|
$amountMatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If both, update!
|
||||||
|
*/
|
||||||
|
if ($wordMatch && $amountMatch) {
|
||||||
|
$journal->recurringTransaction()->associate($recurring);
|
||||||
|
$journal->save();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,10 +99,7 @@ class EloquentRecurringTrigger
|
|||||||
*/
|
*/
|
||||||
public function subscribe(Dispatcher $events)
|
public function subscribe(Dispatcher $events)
|
||||||
{
|
{
|
||||||
// $events->listen('recurring.destroy', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@destroy');
|
$events->listen('recurring.rescan', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@rescan');
|
||||||
// $events->listen('recurring.store', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@store');
|
|
||||||
// $events->listen('recurring.update', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@update');
|
|
||||||
// $events->listen('recurring.check', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@createReminders');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -104,68 +104,6 @@ class Piggybank extends Ardent
|
|||||||
return ['created_at', 'updated_at', 'targetdate', 'startdate'];
|
return ['created_at', 'updated_at', 'targetdate', 'startdate'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Firefly shouldn't create piggybank repetions that completely
|
|
||||||
* lie in the future, so we should be able to safely grab the "latest"
|
|
||||||
* one and use that to calculate when the user will be reminded.
|
|
||||||
*/
|
|
||||||
public function nextReminderDate()
|
|
||||||
{
|
|
||||||
if (is_null($this->reminder)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
/** @var \PiggybankRepetition $rep */
|
|
||||||
$rep = $this->currentRelevantRep();
|
|
||||||
$today = new Carbon;
|
|
||||||
if ($rep && is_null($rep->startdate)) {
|
|
||||||
switch ($this->reminder) {
|
|
||||||
case 'day':
|
|
||||||
return $today;
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
return $today->endOfWeek();
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
return $today->endOfMonth();
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
return $today->endOfYear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if ($rep && !is_null($rep->startdate)) {
|
|
||||||
// start with the start date
|
|
||||||
// when its bigger than today, return it:
|
|
||||||
$start = clone $rep->startdate;
|
|
||||||
while ($start <= $today) {
|
|
||||||
switch ($this->reminder) {
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
break;
|
|
||||||
case 'day':
|
|
||||||
$start->addDay();
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
$start->addWeek();
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
$start->addMonth();
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
$start->addYear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $start;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Carbon;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grabs the PiggyBankRepetition that's currently relevant / active
|
* Grabs the PiggyBankRepetition that's currently relevant / active
|
||||||
*
|
*
|
||||||
@@ -222,14 +160,6 @@ class Piggybank extends Ardent
|
|||||||
return $this->hasMany('PiggybankEvent');
|
return $this->hasMany('PiggybankEvent');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function piggybankreminders()
|
|
||||||
{
|
|
||||||
return $this->hasMany('PiggybankReminder');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same but for specific date.
|
* Same but for specific date.
|
||||||
*
|
*
|
||||||
|
@@ -1,105 +0,0 @@
|
|||||||
<?php
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PiggybankReminder
|
|
||||||
*
|
|
||||||
* @property integer $id
|
|
||||||
* @property \Carbon\Carbon $created_at
|
|
||||||
* @property \Carbon\Carbon $updated_at
|
|
||||||
* @property string $class
|
|
||||||
* @property integer $piggybank_id
|
|
||||||
* @property integer $recurring_transaction_id
|
|
||||||
* @property integer $user_id
|
|
||||||
* @property \Carbon\Carbon $startdate
|
|
||||||
* @property \Carbon\Carbon $enddate
|
|
||||||
* @property boolean $active
|
|
||||||
* @property-read \Piggybank $piggybank
|
|
||||||
* @property-read \RecurringTransaction $recurringTransaction
|
|
||||||
* @property-read \User $user
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereCreatedAt($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereUpdatedAt($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereClass($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder wherePiggybankId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereRecurringTransactionId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereUserId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereStartdate($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereEnddate($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\PiggybankReminder whereActive($value)
|
|
||||||
* @method static \Reminder validOn($date)
|
|
||||||
* @method static \Reminder validOnOrAfter($date)
|
|
||||||
*/
|
|
||||||
class PiggybankReminder extends Reminder
|
|
||||||
{
|
|
||||||
protected $isSubclass = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will render a string telling you something about what to save or something.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
/** @var \Piggybank $piggyBank */
|
|
||||||
$piggyBank = $this->piggybank;
|
|
||||||
|
|
||||||
|
|
||||||
$fullText
|
|
||||||
= 'In order to save enough money for <a href="' . route('piggybanks.show', $piggyBank->id) . '">"' . e(
|
|
||||||
$piggyBank->name
|
|
||||||
) . '"</a> you';
|
|
||||||
|
|
||||||
$fullText .= ' should save at least ' . mf($this->amountToSave(), false) . ' this ' . $piggyBank->reminder
|
|
||||||
. ', before ' . $this->enddate->format('M jS, Y');
|
|
||||||
|
|
||||||
return $fullText;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return float
|
|
||||||
* @throws Firefly\Exception\FireflyException
|
|
||||||
*/
|
|
||||||
public function amountToSave()
|
|
||||||
{
|
|
||||||
/** @var \Piggybank $piggyBank */
|
|
||||||
$piggyBank = $this->piggybank;
|
|
||||||
/** @var \PiggybankRepetition $repetition */
|
|
||||||
$repetition = $piggyBank->currentRelevantRep();
|
|
||||||
|
|
||||||
// if the target date of the repetition is zero, we use the created_at date of the repetition
|
|
||||||
// and add two years; it's the same routine used elsewhere.
|
|
||||||
if (is_null($repetition->targetdate)) {
|
|
||||||
$targetdate = clone $repetition->created_at;
|
|
||||||
$targetdate->addYears(2);
|
|
||||||
} else {
|
|
||||||
$targetdate = $repetition->targetdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$today = new Carbon;
|
|
||||||
$diff = $today->diff($targetdate);
|
|
||||||
$left = $piggyBank->targetamount - $repetition->currentamount;
|
|
||||||
// to prevent devide by zero:
|
|
||||||
$piggyBank->reminder_skip = $piggyBank->reminder_skip < 1 ? 1 : $piggyBank->reminder_skip;
|
|
||||||
$toSave = 0;
|
|
||||||
switch ($piggyBank->reminder) {
|
|
||||||
case 'day':
|
|
||||||
$toSave = $left;// / ($diff->days / $piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
$weeks = ceil($diff->days / 7);
|
|
||||||
$toSave = $left / ($weeks / $piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
$toSave = $left / ($diff->m / $piggyBank->reminder_skip);
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
throw new \Firefly\Exception\FireflyException('No impl year reminder/ PiggyBankReminder Render');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return floatval($toSave);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -62,15 +62,6 @@ class RecurringTransaction extends Ardent
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function reminders()
|
|
||||||
{
|
|
||||||
return $this->hasMany('RecurringTransactionReminder');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Carbon
|
* @return Carbon
|
||||||
*/
|
*/
|
||||||
|
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RecurringTransactionReminder
|
|
||||||
*
|
|
||||||
* @property integer $id
|
|
||||||
* @property \Carbon\Carbon $created_at
|
|
||||||
* @property \Carbon\Carbon $updated_at
|
|
||||||
* @property string $class
|
|
||||||
* @property integer $piggybank_id
|
|
||||||
* @property integer $recurring_transaction_id
|
|
||||||
* @property integer $user_id
|
|
||||||
* @property \Carbon\Carbon $startdate
|
|
||||||
* @property \Carbon\Carbon $enddate
|
|
||||||
* @property boolean $active
|
|
||||||
* @property-read \Piggybank $piggybank
|
|
||||||
* @property-read \RecurringTransaction $recurringTransaction
|
|
||||||
* @property-read \User $user
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereCreatedAt($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereUpdatedAt($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereClass($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder wherePiggybankId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereRecurringTransactionId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereUserId($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereStartdate($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereEnddate($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\RecurringTransactionReminder whereActive($value)
|
|
||||||
* @method static \Reminder validOn($date)
|
|
||||||
* @method static \Reminder validOnOrAfter($date)
|
|
||||||
*/
|
|
||||||
class RecurringTransactionReminder extends Reminder
|
|
||||||
{
|
|
||||||
protected $isSubclass = true;
|
|
||||||
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return '123';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Firefly\Database\SingleTableInheritanceEntity;
|
use Firefly\Database\SingleTableInheritanceEntity;
|
||||||
|
use LaravelBook\Ardent\Ardent;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reminder
|
* Reminder
|
||||||
@@ -10,33 +12,24 @@ use Firefly\Database\SingleTableInheritanceEntity;
|
|||||||
* @property \Carbon\Carbon $created_at
|
* @property \Carbon\Carbon $created_at
|
||||||
* @property \Carbon\Carbon $updated_at
|
* @property \Carbon\Carbon $updated_at
|
||||||
* @property string $class
|
* @property string $class
|
||||||
* @property integer $piggybank_id
|
|
||||||
* @property integer $recurring_transaction_id
|
|
||||||
* @property integer $user_id
|
* @property integer $user_id
|
||||||
* @property \Carbon\Carbon $startdate
|
* @property \Carbon\Carbon $startdate
|
||||||
* @property \Carbon\Carbon $enddate
|
* @property \Carbon\Carbon $enddate
|
||||||
* @property boolean $active
|
* @property boolean $active
|
||||||
* @property-read \Piggybank $piggybank
|
|
||||||
* @property-read \RecurringTransaction $recurringTransaction
|
|
||||||
* @property-read \User $user
|
* @property-read \User $user
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereId($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereId($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereCreatedAt($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereCreatedAt($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereUpdatedAt($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereUpdatedAt($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereClass($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereClass($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder wherePiggybankId($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereUserId($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereRecurringTransactionId($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereStartdate($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereUserId($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereEnddate($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereStartdate($value)
|
* @method static \Illuminate\Database\Query\Builder|\Reminder whereActive($value)
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereEnddate($value)
|
|
||||||
* @method static \Illuminate\Database\Query\Builder|\Reminder whereActive($value)
|
|
||||||
* @method static \Reminder validOn($date)
|
|
||||||
* @method static \Reminder validOnOrAfter($date)
|
|
||||||
*/
|
*/
|
||||||
class Reminder extends SingleTableInheritanceEntity
|
class Reminder extends Ardent
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $table = 'reminders';
|
protected $table = 'reminders';
|
||||||
protected $subclassField = 'class';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,49 +40,6 @@ class Reminder extends SingleTableInheritanceEntity
|
|||||||
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function piggybank()
|
|
||||||
{
|
|
||||||
return $this->belongsTo('Piggybank');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function recurringTransaction()
|
|
||||||
{
|
|
||||||
return $this->belongsTo('RecurringTransaction');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function scopeValidOn($query, Carbon $date)
|
|
||||||
{
|
|
||||||
return $query->where('startdate', '<=', $date->format('Y-m-d'))->where('enddate', '>=', $date->format('Y-m-d'))
|
|
||||||
->where('active', 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function scopeValidOnOrAfter($query, Carbon $date)
|
|
||||||
{
|
|
||||||
return $query->where(
|
|
||||||
function ($q) use ($date) {
|
|
||||||
$q->where('startdate', '<=', $date->format('Y-m-d'))->where(
|
|
||||||
'enddate', '>=', $date->format('Y-m-d')
|
|
||||||
);
|
|
||||||
$q->orWhere(
|
|
||||||
function ($q) use ($date) {
|
|
||||||
$q->where('startdate', '>=', $date);
|
|
||||||
$q->where('enddate', '>=', $date);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)->where('active', 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User
|
* User
|
||||||
*
|
*
|
||||||
|
@@ -215,6 +215,30 @@ use LaravelBook\Ardent\Builder;
|
|||||||
* 'Budget[] $budgets
|
* 'Budget[] $budgets
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
* 'Category[] $categories
|
* 'Category[] $categories
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Budget[] $budgets
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Category[] $categories
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Budget[] $budgets
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Category[] $categories
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Budget[] $budgets
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Category[] $categories
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Budget[] $budgets
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Category[] $categories
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Budget[] $budgets
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Category[] $categories
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Budget[] $budgets
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||||
|
* 'Category[] $categories
|
||||||
*/
|
*/
|
||||||
class TransactionJournal extends Ardent
|
class TransactionJournal extends Ardent
|
||||||
{
|
{
|
||||||
|
@@ -78,22 +78,6 @@ class User extends Ardent implements UserInterface, RemindableInterface
|
|||||||
return $this->hasMany('Budget');
|
return $this->hasMany('Budget');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function reminders()
|
|
||||||
{
|
|
||||||
return $this->hasMany('Reminder');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function piggybankreminders()
|
|
||||||
{
|
|
||||||
return $this->hasMany('PiggybankReminder');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
|
@@ -133,6 +133,7 @@ Route::group(['before' => 'auth'], function () {
|
|||||||
// some date routes:
|
// some date routes:
|
||||||
Route::get('/prev',['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']);
|
Route::get('/prev',['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']);
|
||||||
Route::get('/next',['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
|
Route::get('/next',['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
|
||||||
|
Route::get('/jump/{range}',['uses' => 'HomeController@rangeJump','as' => 'rangeJump']);
|
||||||
|
|
||||||
// account controller:
|
// account controller:
|
||||||
Route::get('/accounts', ['uses' => 'AccountController@index', 'as' => 'accounts.index']);
|
Route::get('/accounts', ['uses' => 'AccountController@index', 'as' => 'accounts.index']);
|
||||||
@@ -169,6 +170,7 @@ Route::group(['before' => 'auth'], function () {
|
|||||||
Route::get('/chart/home/budgets', ['uses' => 'ChartController@homeBudgets', 'as' => 'chart.budgets']);
|
Route::get('/chart/home/budgets', ['uses' => 'ChartController@homeBudgets', 'as' => 'chart.budgets']);
|
||||||
Route::get('/chart/home/info/{accountnameA}/{day}/{month}/{year}', ['uses' => 'ChartController@homeAccountInfo', 'as' => 'chart.info']);
|
Route::get('/chart/home/info/{accountnameA}/{day}/{month}/{year}', ['uses' => 'ChartController@homeAccountInfo', 'as' => 'chart.info']);
|
||||||
Route::get('/chart/categories/show/{category}', ['uses' => 'ChartController@categoryShowChart','as' => 'chart.showcategory']);
|
Route::get('/chart/categories/show/{category}', ['uses' => 'ChartController@categoryShowChart','as' => 'chart.showcategory']);
|
||||||
|
Route::get('/chart/home/recurring', ['uses' => 'ChartController@homeRecurring', 'as' => 'chart.recurring']);
|
||||||
// (new charts for budgets)
|
// (new charts for budgets)
|
||||||
Route::get('/chart/budget/{budget}/default', ['uses' => 'ChartController@budgetDefault', 'as' => 'chart.budget.default']);
|
Route::get('/chart/budget/{budget}/default', ['uses' => 'ChartController@budgetDefault', 'as' => 'chart.budget.default']);
|
||||||
Route::get('chart/budget/{budget}/no_envelope', ['uses' => 'ChartController@budgetNoLimits', 'as' => 'chart.budget.nolimit']);
|
Route::get('chart/budget/{budget}/no_envelope', ['uses' => 'ChartController@budgetNoLimits', 'as' => 'chart.budget.nolimit']);
|
||||||
@@ -187,6 +189,7 @@ Route::group(['before' => 'auth'], function () {
|
|||||||
Route::get('/json/revenue', ['uses' => 'JsonController@revenue', 'as' => 'json.revenue']);
|
Route::get('/json/revenue', ['uses' => 'JsonController@revenue', 'as' => 'json.revenue']);
|
||||||
Route::get('/json/transfers', ['uses' => 'JsonController@transfers', 'as' => 'json.transfers']);
|
Route::get('/json/transfers', ['uses' => 'JsonController@transfers', 'as' => 'json.transfers']);
|
||||||
Route::get('/json/recurring', ['uses' => 'JsonController@recurring', 'as' => 'json.recurring']);
|
Route::get('/json/recurring', ['uses' => 'JsonController@recurring', 'as' => 'json.recurring']);
|
||||||
|
Route::get('/json/recurringjournals/{recurring}', ['uses' => 'JsonController@recurringjournals', 'as' => 'json.recurringjournals']);
|
||||||
|
|
||||||
// limit controller:
|
// limit controller:
|
||||||
Route::get('/budgets/limits/create/{budget?}',['uses' => 'LimitController@create','as' => 'budgets.limits.create']);
|
Route::get('/budgets/limits/create/{budget?}',['uses' => 'LimitController@create','as' => 'budgets.limits.create']);
|
||||||
@@ -217,16 +220,11 @@ Route::group(['before' => 'auth'], function () {
|
|||||||
// recurring transactions controller
|
// recurring transactions controller
|
||||||
Route::get('/recurring',['uses' => 'RecurringController@index', 'as' => 'recurring.index']);
|
Route::get('/recurring',['uses' => 'RecurringController@index', 'as' => 'recurring.index']);
|
||||||
Route::get('/recurring/show/{recurring}',['uses' => 'RecurringController@show', 'as' => 'recurring.show']);
|
Route::get('/recurring/show/{recurring}',['uses' => 'RecurringController@show', 'as' => 'recurring.show']);
|
||||||
|
Route::get('/recurring/rescan/{recurring}',['uses' => 'RecurringController@rescan', 'as' => 'recurring.rescan']);
|
||||||
Route::get('/recurring/create',['uses' => 'RecurringController@create', 'as' => 'recurring.create']);
|
Route::get('/recurring/create',['uses' => 'RecurringController@create', 'as' => 'recurring.create']);
|
||||||
Route::get('/recurring/edit/{recurring}',['uses' => 'RecurringController@edit','as' => 'recurring.edit']);
|
Route::get('/recurring/edit/{recurring}',['uses' => 'RecurringController@edit','as' => 'recurring.edit']);
|
||||||
Route::get('/recurring/delete/{recurring}',['uses' => 'RecurringController@delete','as' => 'recurring.delete']);
|
Route::get('/recurring/delete/{recurring}',['uses' => 'RecurringController@delete','as' => 'recurring.delete']);
|
||||||
|
|
||||||
// reminder controller
|
|
||||||
Route::get('/reminders/dialog',['uses' => 'ReminderController@modalDialog']);
|
|
||||||
Route::post('/reminders/postpone/{reminder}',['uses' => 'ReminderController@postpone']);
|
|
||||||
Route::post('/reminders/dismiss/{reminder}',['uses' => 'ReminderController@dismiss']);
|
|
||||||
Route::get('/reminders/redirect/{reminder}',['uses' => 'ReminderController@redirect']);
|
|
||||||
|
|
||||||
// report controller:
|
// report controller:
|
||||||
Route::get('/reports',['uses' => 'ReportController@index','as' => 'reports.index']);
|
Route::get('/reports',['uses' => 'ReportController@index','as' => 'reports.index']);
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||||
<h2><a href="{{route('accounts.create')}}">Start from scratch</a></h2>
|
<h2><a href="{{route('accounts.create','asset')}}">Start from scratch</a></h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Use this option if you are new to Firefly (III).
|
Use this option if you are new to Firefly (III).
|
||||||
@@ -29,9 +29,10 @@
|
|||||||
@else
|
@else
|
||||||
|
|
||||||
|
|
||||||
<!-- ACCOUNTS -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8 col-md-12 col-sm-12">
|
<div class="col-lg-8 col-md-12 col-sm-12">
|
||||||
|
<!-- ACCOUNTS -->
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-credit-card fa-fw"></i> <a href="#">Your accounts</a>
|
<i class="fa fa-credit-card fa-fw"></i> <a href="#">Your accounts</a>
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
<div id="accounts-chart" style="height:300px;"></div>
|
<div id="accounts-chart" style="height:300px;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- BUDGETS -->
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-tasks fa-fw"></i> <a href="{{route('budgets.index.date')}}">Budgets and spending</a>
|
<i class="fa fa-tasks fa-fw"></i> <a href="{{route('budgets.index.date')}}">Budgets and spending</a>
|
||||||
@@ -48,6 +50,7 @@
|
|||||||
<div id="budgets"></div>
|
<div id="budgets"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- CATEGORIES -->
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-bar-chart fa-fw"></i> <a href="{{route('categories.index')}}">Categories</a>
|
<i class="fa fa-bar-chart fa-fw"></i> <a href="{{route('categories.index')}}">Categories</a>
|
||||||
@@ -55,8 +58,15 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div id="categories"></div>
|
<div id="categories"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-line-chart"></i> Savings
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
Bla bla
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -65,6 +75,16 @@
|
|||||||
<!-- time based navigation -->
|
<!-- time based navigation -->
|
||||||
@include('partials.date_nav')
|
@include('partials.date_nav')
|
||||||
|
|
||||||
|
<!-- REMINDERS -->
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-line-chart"></i> Recurring transactions
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="recurring"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- TRANSACTIONS -->
|
<!-- TRANSACTIONS -->
|
||||||
@foreach($transactions as $data)
|
@foreach($transactions as $data)
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
@@ -2,6 +2,22 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-clock-o fa-fw"></i>
|
<i class="fa fa-clock-o fa-fw"></i>
|
||||||
{{{\Session::get('period')}}}
|
{{{\Session::get('period')}}}
|
||||||
|
|
||||||
|
<!-- ACTIONS MENU -->
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||||
|
Range
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu pull-right" role="menu">
|
||||||
|
@foreach(Config::get('firefly.range_to_name') as $name => $label)
|
||||||
|
<li><a href="{{route('rangeJump',$name)}}"><i class="fa fa-calendar fa-fw"></i> {{{ucfirst($label)}}}</a></li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="btn-group btn-group-sm btn-group-justified">
|
<div class="btn-group btn-group-sm btn-group-justified">
|
||||||
|
@@ -57,7 +57,7 @@
|
|||||||
Target date: {{$piggyBank->targetdate->format('M jS, Y')}}<br />
|
Target date: {{$piggyBank->targetdate->format('M jS, Y')}}<br />
|
||||||
@endif
|
@endif
|
||||||
@if(!is_null($piggyBank->reminder))
|
@if(!is_null($piggyBank->reminder))
|
||||||
Next reminder: {{$piggyBank->nextReminderDate()->format('M jS, Y')}} ({{$piggyBank->reminder}})
|
Next reminder: TODO
|
||||||
@endif
|
@endif
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
|
|
||||||
@if(!is_null($repeated->reminder))
|
@if(!is_null($repeated->reminder))
|
||||||
<small>
|
<small>
|
||||||
Next reminder: {{$repeated->nextReminderDate()->format('M jS, Y')}} ({{$piggyBank->reminder}})
|
Next reminder: TODO
|
||||||
</small>
|
</small>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@@ -1,43 +1,41 @@
|
|||||||
@extends('layouts.default')
|
@extends('layouts.default')
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
|
||||||
<p class="text-info">
|
|
||||||
Use this extremely obvious form to change your password.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||||
|
<div class="panel panel-primary">
|
||||||
{{Form::open(['class' => 'form-horizontal'])}}
|
<div class="panel-heading">
|
||||||
<div class="form-group">
|
Change your password
|
||||||
<label for="inputOldPassword" class="col-sm-4 control-label">Old password</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="password" class="form-control" id="inputOldPassword" placeholder="Old password" name="old">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{Form::open(['class' => 'form-horizontal'])}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="inputOldPassword" class="col-sm-4 control-label">Old password</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="password" class="form-control" id="inputOldPassword" placeholder="Old password" name="old">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="inputNewPassword1" class="col-sm-4 control-label">New password</label>
|
<label for="inputNewPassword1" class="col-sm-4 control-label">New password</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="password" class="form-control" id="inputNewPassword1" placeholder="New password" name="new1">
|
<input type="password" class="form-control" id="inputNewPassword1" placeholder="New password" name="new1">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="inputNewPassword2" class="col-sm-4 control-label">New password (again)</label>
|
<label for="inputNewPassword2" class="col-sm-4 control-label">New password (again)</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="password" class="form-control" id="inputNewPassword2" placeholder="New password (again)" name="new2">
|
<input type="password" class="form-control" id="inputNewPassword2" placeholder="New password (again)" name="new2">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-4 col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-success">Change your password</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{Form::close()}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<div class="col-sm-offset-4 col-sm-10">
|
|
||||||
<button type="submit" class="btn btn-success">Change your password</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{Form::close()}}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
@@ -1,8 +1,15 @@
|
|||||||
@extends('layouts.default')
|
@extends('layouts.default')
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||||
<p class="lead"><a href="{{route('change-password')}}">Change your password</a></p>
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading">
|
||||||
|
Options
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<a href="{{route('change-password')}}">Change your password</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
@@ -1,68 +1,108 @@
|
|||||||
@extends('layouts.default')
|
@extends('layouts.default')
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
<div class="col-lg-6 col-sm-12 col-md-12">
|
||||||
<p class="lead">Use recurring transactions to track repeated withdrawals</p>
|
<div class="panel panel-default">
|
||||||
<p>
|
<div class="panel-heading">
|
||||||
<div class="btn-group btn-group-xs">
|
<i class="fa fa-rotate-right"></i> {{{$recurring->name}}}
|
||||||
<a href="{{route('recurring.edit',$recurring->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span> edit</a>
|
|
||||||
<a href="{{route('recurring.delete',$recurring->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> delete</a>
|
@if($recurring->active)
|
||||||
</div>
|
<span class="glyphicon glyphicon-ok" title="Active"></span>
|
||||||
</p>
|
@else
|
||||||
|
<span class="glyphicon glyphicon-remove" title="Inactive"></span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($recurring->automatch)
|
||||||
|
<span class="glyphicon glyphicon-ok" title="Automatically matched by Firefly"></span>
|
||||||
|
@else
|
||||||
|
<span class="glyphicon glyphicon-remove" title="Not automatically matched by Firefly"></span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- ACTIONS MENU -->
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||||
|
Actions
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu pull-right" role="menu">
|
||||||
|
<li><a href="{{route('recurring.edit',$recurring->id)}}"><span class="glyphicon glyphicon-pencil"></span> edit</a></li>
|
||||||
|
<li><a href="{{route('recurring.delete',$recurring->id)}}"><span class="glyphicon glyphicon-trash"></span> delete</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
Matching on
|
||||||
|
@foreach(explode(' ',$recurring->match) as $word)
|
||||||
|
<span class="label label-info">{{{$word}}}</span>
|
||||||
|
@endforeach
|
||||||
|
between {{mf($recurring->amount_min)}} and {{mf($recurring->amount_max)}}.
|
||||||
|
Repeats {{$recurring->repeat_freq}}.</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Next reminder</td>
|
||||||
|
<td>TODO TODO</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-sm-12 col-md-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
More
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
<a href="{{route('recurring.rescan',$recurring->id)}}" class="btn btn-default">Rescan old transactions</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-sm-6 col-md-12">
|
<div class="col-lg-12 col-sm-12 col-md-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
<table class="table">
|
<div class="panel-heading">
|
||||||
<tr>
|
Connected transaction journals
|
||||||
<td>Matches on: </td>
|
</div>
|
||||||
<td>
|
<div class="panel-body">
|
||||||
@foreach(explode(' ',$recurring->match) as $word)
|
<table id="transactionTable" class="table table-striped table-bordered" >
|
||||||
<span class="label label-info">{{{$word}}}</span>
|
<thead>
|
||||||
@endforeach
|
<tr>
|
||||||
</td>
|
<th>Date</th>
|
||||||
</tr>
|
<th>Description</th>
|
||||||
<tr>
|
<th>Amount (€)</th>
|
||||||
<td>Between</td>
|
<th>From</th>
|
||||||
<td> {{mf($recurring->amount_min)}} – {{mf($recurring->amount_max)}}</td>
|
<th>To</th>
|
||||||
</tr>
|
<th>Budget / category</th>
|
||||||
<tr>
|
<th>ID</th>
|
||||||
<td>Repeats</td>
|
</tr>
|
||||||
<td>{{ucfirst($recurring->repeat_freq)}}</td>
|
</thead>
|
||||||
</tr>
|
</table>
|
||||||
<tr>
|
</div>
|
||||||
<td>Next reminder</td>
|
</div>
|
||||||
<td>{{$recurring->next()->format('d-m-Y')}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Will be auto-matched</td>
|
|
||||||
<td>
|
|
||||||
@if($recurring->automatch)
|
|
||||||
<span class="glyphicon glyphicon-ok"></span>
|
|
||||||
@else
|
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Is active</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
@if($recurring->active)
|
|
||||||
<span class="glyphicon glyphicon-ok"></span>
|
|
||||||
@else
|
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
var URL = '{{route('json.recurringjournals',$recurring->id)}}';
|
||||||
|
</script>
|
||||||
|
{{HTML::script('assets/javascript/typeahead/bootstrap3-typeahead.min.js')}}
|
||||||
|
{{HTML::script('assets/javascript/datatables/jquery.dataTables.min.js')}}
|
||||||
|
{{HTML::script('assets/javascript/datatables/dataTables.bootstrap.js')}}
|
||||||
|
{{HTML::script('assets/javascript/firefly/recurring.js')}}
|
||||||
|
@stop
|
||||||
|
@section('styles')
|
||||||
|
{{HTML::style('assets/stylesheets/datatables/dataTables.bootstrap.css')}}
|
||||||
@stop
|
@stop
|
@@ -1,24 +0,0 @@
|
|||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close"
|
|
||||||
data-dismiss="modal"><span aria-hidden="true">×</span>
|
|
||||||
<span class="sr-only">Close</span></button>
|
|
||||||
<h4 class="modal-title">Reminders</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<table class="table">
|
|
||||||
@foreach($reminders as $reminder)
|
|
||||||
<tr class="reminder-row-{{$reminder->id}}">
|
|
||||||
<td>{{$reminder->render()}}</td>
|
|
||||||
<td style="width:50%;">
|
|
||||||
<a href="#" data-id="{{$reminder->id}}" class="dismiss-24 btn btn-danger btn-sm">Postpone (24hrs)</a>
|
|
||||||
<a href="#" data-id="{{$reminder->id}}" class="dismiss-forever btn btn-danger btn-sm">Dismiss (forever)</a>
|
|
||||||
<a href="#" data-id="{{$reminder->id}}" class="do-it btn btn-success btn-sm">I want to do this</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
@endforeach
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
@@ -17,7 +17,7 @@ $(function () {
|
|||||||
allowDecimals: false,
|
allowDecimals: false,
|
||||||
labels: {
|
labels: {
|
||||||
formatter: function () {
|
formatter: function () {
|
||||||
if(this.value >= 1000 || this.value <= -1000) {
|
if (this.value >= 1000 || this.value <= -1000) {
|
||||||
return '\u20AC ' + (this.value / 1000) + 'k';
|
return '\u20AC ' + (this.value / 1000) + 'k';
|
||||||
}
|
}
|
||||||
return '\u20AC ' + this.value;
|
return '\u20AC ' + this.value;
|
||||||
@@ -36,10 +36,10 @@ $(function () {
|
|||||||
text: null
|
text: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {enabled:false},
|
legend: {enabled: false},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
formatter: function () {
|
formatter: function () {
|
||||||
return this.series.name + ': \u20AC ' + Highcharts.numberFormat(this.y,2);
|
return this.series.name + ': \u20AC ' + Highcharts.numberFormat(this.y, 2);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plotOptions: {
|
plotOptions: {
|
||||||
@@ -101,7 +101,7 @@ $(function () {
|
|||||||
},
|
},
|
||||||
labels: {
|
labels: {
|
||||||
formatter: function () {
|
formatter: function () {
|
||||||
if(this.value >= 1000 || this.value <= -1000) {
|
if (this.value >= 1000 || this.value <= -1000) {
|
||||||
return '\u20AC ' + (this.value / 1000) + 'k';
|
return '\u20AC ' + (this.value / 1000) + 'k';
|
||||||
}
|
}
|
||||||
return '\u20AC ' + this.value;
|
return '\u20AC ' + this.value;
|
||||||
@@ -165,17 +165,17 @@ $(function () {
|
|||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
formatter: function () {
|
formatter: function () {
|
||||||
return this.series.name + ': \u20AC ' + Highcharts.numberFormat(this.y,2);
|
return this.series.name + ': \u20AC ' + Highcharts.numberFormat(this.y, 2);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
min: 0,
|
min: 0,
|
||||||
title: {text:null},
|
title: {text: null},
|
||||||
|
|
||||||
labels: {
|
labels: {
|
||||||
overflow: 'justify',
|
overflow: 'justify',
|
||||||
formatter: function () {
|
formatter: function () {
|
||||||
if(this.value >= 1000 || this.value <= -1000) {
|
if (this.value >= 1000 || this.value <= -1000) {
|
||||||
return '\u20AC ' + (this.value / 1000) + 'k';
|
return '\u20AC ' + (this.value / 1000) + 'k';
|
||||||
}
|
}
|
||||||
return '\u20AC ' + this.value;
|
return '\u20AC ' + this.value;
|
||||||
@@ -188,7 +188,7 @@ $(function () {
|
|||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
events: {
|
events: {
|
||||||
click: function (e) {
|
click: function (e) {
|
||||||
if(e.point.url != null) {
|
if (e.point.url != null) {
|
||||||
window.location = e.point.url;
|
window.location = e.point.url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ $(function () {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
enabled: false,
|
enabled: false
|
||||||
},
|
},
|
||||||
credits: {
|
credits: {
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -211,5 +211,46 @@ $(function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$.getJSON('chart/home/recurring').success(function (data) {
|
||||||
|
if (data[0].data.length == 0) {
|
||||||
|
$('#recurring').parent().parent().remove();
|
||||||
|
} else {
|
||||||
|
$('#recurring').highcharts({
|
||||||
|
title: {
|
||||||
|
text: null
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
formatter: function () {
|
||||||
|
if (this.point.objType == 'paid') {
|
||||||
|
return this.key + ': \u20AC ' + Highcharts.numberFormat(this.y, 2);
|
||||||
|
} else {
|
||||||
|
return this.key + ': ~\u20AC ' + Highcharts.numberFormat(this.y, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
pie: {
|
||||||
|
events: {
|
||||||
|
click: function (e) {
|
||||||
|
if (e.point.url != null) {
|
||||||
|
window.location = e.point.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
allowPointSelect: true,
|
||||||
|
cursor: 'pointer',
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
@@ -1,112 +1,204 @@
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#recurringTable').DataTable(
|
if ($('#recurringTable').length > 0) {
|
||||||
{
|
$('#recurringTable').DataTable(
|
||||||
serverSide: true,
|
|
||||||
ajax: URL,
|
|
||||||
paging: true,
|
|
||||||
processing: true,
|
|
||||||
order: [],
|
|
||||||
"lengthMenu": [[50, 100, 250, -1], [50, 100, 250, "All"]],
|
|
||||||
columns: [
|
|
||||||
{
|
{
|
||||||
name: 'name',
|
serverSide: true,
|
||||||
data: 'name',
|
ajax: URL,
|
||||||
searchable: true,
|
paging: true,
|
||||||
title: 'Name',
|
processing: true,
|
||||||
render: function (data) {
|
order: [],
|
||||||
return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
"lengthMenu": [[50, 100, 250, -1], [50, 100, 250, "All"]],
|
||||||
}
|
columns: [
|
||||||
},
|
{
|
||||||
{
|
name: 'name',
|
||||||
name: 'match',
|
data: 'name',
|
||||||
data: 'match',
|
searchable: true,
|
||||||
searchable: true,
|
title: 'Name',
|
||||||
title: 'Matches on',
|
render: function (data) {
|
||||||
render: function (data) {
|
return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
||||||
var str = '';
|
}
|
||||||
for (x in data) {
|
},
|
||||||
str += '<span class="label label-info">' + data[x] + '</span> ';
|
{
|
||||||
}
|
name: 'match',
|
||||||
return str;//return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
data: 'match',
|
||||||
}
|
searchable: true,
|
||||||
},
|
title: 'Matches on',
|
||||||
{
|
render: function (data) {
|
||||||
name: 'amount_min',
|
var str = '';
|
||||||
data: 'amount_min',
|
for (x in data) {
|
||||||
searchable: false,
|
str += '<span class="label label-info">' + data[x] + '</span> ';
|
||||||
title: '→',
|
}
|
||||||
render: function (data) {
|
return str;//return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
||||||
return '<span class="text-info">\u20AC ' + data.toFixed(2) + '</span>';
|
}
|
||||||
}
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'amount_min',
|
||||||
name: 'amount_max',
|
data: 'amount_min',
|
||||||
data: 'amount_max',
|
searchable: false,
|
||||||
searchable: false,
|
title: '→',
|
||||||
title: '←',
|
render: function (data) {
|
||||||
render: function (data) {
|
return '<span class="text-info">\u20AC ' + data.toFixed(2) + '</span>';
|
||||||
return '<span class="text-info">\u20AC ' + data.toFixed(2) + '</span>';
|
}
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name: 'amount_max',
|
||||||
|
data: 'amount_max',
|
||||||
|
searchable: false,
|
||||||
|
title: '←',
|
||||||
|
render: function (data) {
|
||||||
|
return '<span class="text-info">\u20AC ' + data.toFixed(2) + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'date',
|
name: 'date',
|
||||||
data: 'date',
|
data: 'date',
|
||||||
title: 'Expected on',
|
title: 'Expected on',
|
||||||
searchable: false
|
searchable: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'active',
|
name: 'active',
|
||||||
data: 'active',
|
data: 'active',
|
||||||
searchable: false,
|
searchable: false,
|
||||||
sortable: false,
|
sortable: false,
|
||||||
render: function(data) {
|
render: function (data) {
|
||||||
if(data == 1) {
|
if (data == 1) {
|
||||||
return '<i class="fa fa-check fa-faw"></i>';
|
return '<i class="fa fa-check fa-faw"></i>';
|
||||||
} else {
|
} else {
|
||||||
return '<i class="fa fa-remove fa-faw"></i>';
|
return '<i class="fa fa-remove fa-faw"></i>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: 'Is active?'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'automatch',
|
||||||
|
data: 'automatch',
|
||||||
|
sortable: false,
|
||||||
|
searchable: false,
|
||||||
|
render: function (data) {
|
||||||
|
if (data == 1) {
|
||||||
|
return '<i class="fa fa-check fa-faw"></i>';
|
||||||
|
} else {
|
||||||
|
return '<i class="fa fa-remove fa-faw"></i>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: 'Automatch?'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repeat_freq',
|
||||||
|
data: 'repeat_freq',
|
||||||
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
title: 'Repeat frequency'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
data: 'id',
|
||||||
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
title: '',
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
return '<div class="btn-group btn-group-xs">' +
|
||||||
|
'<a class="btn btn-default btn-xs" href="' + data.edit + '">' +
|
||||||
|
'<span class="glyphicon glyphicon-pencil"</a>' +
|
||||||
|
'<a class="btn btn-danger btn-xs" href="' + data.delete + '">' +
|
||||||
|
'<span class="glyphicon glyphicon-trash"</a>' +
|
||||||
|
'</a></div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
title: 'Is active?'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'automatch',
|
|
||||||
data: 'automatch',
|
|
||||||
sortable: false,
|
|
||||||
searchable: false,
|
|
||||||
render: function(data) {
|
|
||||||
if(data == 1) {
|
|
||||||
return '<i class="fa fa-check fa-faw"></i>';
|
|
||||||
} else {
|
|
||||||
return '<i class="fa fa-remove fa-faw"></i>';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: 'Automatch?'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'repeat_freq',
|
|
||||||
data: 'repeat_freq',
|
|
||||||
searchable: false,
|
|
||||||
sortable: false,
|
|
||||||
title: 'Repeat frequency'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
data: 'id',
|
|
||||||
searchable: false,
|
|
||||||
sortable: false,
|
|
||||||
title: '',
|
|
||||||
render: function (data, type, full, meta) {
|
|
||||||
return '<div class="btn-group btn-group-xs">' +
|
|
||||||
'<a class="btn btn-default btn-xs" href="' + data.edit + '">' +
|
|
||||||
'<span class="glyphicon glyphicon-pencil"</a>' +
|
|
||||||
'<a class="btn btn-danger btn-xs" href="' + data.delete + '">' +
|
|
||||||
'<span class="glyphicon glyphicon-trash"</a>' +
|
|
||||||
'</a></div>';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
}
|
}
|
||||||
);
|
if ($('#transactionTable').length > 0) {
|
||||||
});
|
$('#transactionTable').DataTable(
|
||||||
|
{
|
||||||
|
serverSide: true,
|
||||||
|
ajax: URL,
|
||||||
|
paging: true,
|
||||||
|
processing: true,
|
||||||
|
order: [],
|
||||||
|
"lengthMenu": [[50, 100, 250, -1], [50, 100, 250, "All"]],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'date',
|
||||||
|
data: 'date',
|
||||||
|
searchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
data: 'description',
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
icon = 'glyphicon-arrow-left';
|
||||||
|
|
||||||
|
return '<span class="glyphicon ' + icon + '"></span> ' +
|
||||||
|
'<a href="' + data.url + '" title="' + data.description + '">' + data.description + '</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'amount',
|
||||||
|
data: 'amount',
|
||||||
|
'title': 'Amount (\u20AC)',
|
||||||
|
searchable: false,
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
return '<span class="text-danger">\u20AC ' + data.toFixed(2) + '</span>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'from',
|
||||||
|
data: 'from',
|
||||||
|
searchable: false,
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'to',
|
||||||
|
data: 'to',
|
||||||
|
searchable: false,
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'components',
|
||||||
|
data: 'components',
|
||||||
|
searchable: true,
|
||||||
|
sortable: false,
|
||||||
|
title: '',
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
var html = '';
|
||||||
|
if (data.budget_id > 0) {
|
||||||
|
html += '<a href="' + data.budget_url + '" title="' + data.budget_name + '"><i class="fa fa-tasks fa-fw"></i></a> ';
|
||||||
|
}
|
||||||
|
if (data.category_id > 0) {
|
||||||
|
html += '<a href="' + data.category_url + '" title="' + data.category_name + '"><i class="fa fa-bar-chart fa-fw"></i></a> ';
|
||||||
|
}
|
||||||
|
if (data.recurring_id > 0) {
|
||||||
|
html += '<a href="' + data.recurring_url + '" title="' + data.recurring_name + '"><i class="fa fa-rotate-right fa-fw"></i></a> ';
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
data: 'id',
|
||||||
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
title: '',
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
return '<div class="btn-group btn-group-xs">' +
|
||||||
|
'<a class="btn btn-default btn-xs" href="' + data.edit + '">' +
|
||||||
|
'<span class="glyphicon glyphicon-pencil"</a>' +
|
||||||
|
'<a class="btn btn-danger btn-xs" href="' + data.delete + '">' +
|
||||||
|
'<span class="glyphicon glyphicon-trash"</a>' +
|
||||||
|
'</a></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
Reference in New Issue
Block a user