Updates to budgets.

This commit is contained in:
James Cole 2016-04-28 10:59:36 +02:00
parent 19d7e27fa9
commit b47a140c2f
20 changed files with 510 additions and 182 deletions

View File

@ -0,0 +1,50 @@
<?php
/**
* BudgetLimitStored.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Events;
use Carbon\Carbon;
use FireflyIII\Models\BudgetLimit;
use Illuminate\Queue\SerializesModels;
use Log;
/**
* Class BudgetLimitStored
*
* @package FireflyIII\Events
*/
class BudgetLimitStored extends Event
{
use SerializesModels;
/** @var BudgetLimit */
public $budgetLimit;
/** @var Carbon */
public $end; // the only variable we can't get from the budget limit (if necessary).
/**
* BudgetLimitEvents constructor.
*
* @param BudgetLimit $budgetLimit
* @param Carbon $end
*/
public function __construct(BudgetLimit $budgetLimit, Carbon $end)
{
Log::debug('Created new BudgetLimitStored.');
//
$this->budgetLimit = $budgetLimit;
$this->end = $end;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* BudgetLimitUpdated.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Events;
use Carbon\Carbon;
use FireflyIII\Models\BudgetLimit;
use Illuminate\Queue\SerializesModels;
use Log;
/**
* Class BudgetLimitUpdated
*
* @package FireflyIII\Events
*/
class BudgetLimitUpdated extends Event
{
use SerializesModels;
/** @var BudgetLimit */
public $budgetLimit;
/** @var Carbon */
public $end; // the only variable we can't get from the budget limit (if necessary).
/**
* BudgetLimitEvents constructor.
*
* @param BudgetLimit $budgetLimit
* @param Carbon $end
*/
public function __construct(BudgetLimit $budgetLimit, Carbon $end)
{
Log::debug('Created new BudgetLimitUpdated.');
//
$this->budgetLimit = $budgetLimit;
$this->end = $end;
}
}

View File

@ -6,7 +6,6 @@ use Auth;
use ErrorException;
use Exception;
use FireflyIII\Jobs\MailError;
use FireflyIII\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
@ -66,9 +65,14 @@ class Handler extends ExceptionHandler
{
if ($exception instanceof FireflyException || $exception instanceof ErrorException) {
$user = Auth::check() ? Auth::user() : new User;
$userData = [
'id' => 0,
'email' => 'unknown@example.com',
];
if (Auth::check()) {
$userData['id'] = Auth::user()->id;
$userData['email'] = Auth::user()->email;
}
$data = [
'class' => get_class($exception),
'errorMessage' => $exception->getMessage(),
@ -80,7 +84,7 @@ class Handler extends ExceptionHandler
];
// create job that will mail.
$job = new MailError($user, env('SITE_OWNER'), Request::ip(), $data);
$job = new MailError($userData, env('SITE_OWNER'), Request::ip(), $data);
dispatch($job);
}

View File

@ -0,0 +1,105 @@
<?php
/**
* BudgetLimitEventHandler.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\BudgetLimitStored;
use FireflyIII\Events\BudgetLimitUpdated;
use FireflyIII\Models\LimitRepetition;
use Illuminate\Database\QueryException;
use Log;
/**
* Class BudgetLimitEventHandler
*
* @package FireflyIII\Handlers\Events
*/
class BudgetLimitEventHandler
{
/**
* Create the event listener.
*
*/
public function __construct()
{
}
/**
* In a perfect world, the store() routine should be different from the update()
* routine. It would not have to check count() == 0 because there could be NO
* limit repetitions at this point. However, the database can be wrong so we check.
*
* @param BudgetLimitStored $event
*/
public function store(BudgetLimitStored $event)
{
$budgetLimit = $event->budgetLimit;
$end = $event->end;
$set = $budgetLimit->limitrepetitions()
->where('startdate', $budgetLimit->startdate->format('Y-m-d 00:00:00'))
->where('enddate', $end->format('Y-m-d 00:00:00'))
->get();
if ($set->count() == 0) {
$repetition = new LimitRepetition;
$repetition->startdate = $budgetLimit->startdate;
$repetition->enddate = $end;
$repetition->amount = $budgetLimit->amount;
$repetition->budgetLimit()->associate($budgetLimit);
try {
$repetition->save();
} catch (QueryException $e) {
Log::error('Trying to save new LimitRepetition failed: ' . $e->getMessage());
}
}
if ($set->count() == 1) {
$repetition = $set->first();
$repetition->amount = $budgetLimit->amount;
$repetition->save();
}
}
/**
* @param BudgetLimitUpdated $event
*/
public function update(BudgetLimitUpdated $event)
{
$budgetLimit = $event->budgetLimit;
$end = $event->end;
$set = $budgetLimit->limitrepetitions()
->where('startdate', $budgetLimit->startdate->format('Y-m-d 00:00:00'))
->where('enddate', $end->format('Y-m-d 00:00:00'))
->get();
if ($set->count() == 0) {
$repetition = new LimitRepetition;
$repetition->startdate = $budgetLimit->startdate;
$repetition->enddate = $end;
$repetition->amount = $budgetLimit->amount;
$repetition->budgetLimit()->associate($budgetLimit);
try {
$repetition->save();
} catch (QueryException $e) {
Log::error('Trying to save new LimitRepetition failed: ' . $e->getMessage());
}
}
if ($set->count() == 1) {
$repetition = $set->first();
$repetition->amount = $budgetLimit->amount;
$repetition->save();
}
}
}

View File

@ -141,5 +141,13 @@ class BillLine
$this->hit = $hit;
}
/**
* @return bool
*/
public function isHitAndActive():bool
{
return $this->hit && $this->active;
}
}

View File

@ -24,6 +24,54 @@ use Illuminate\Support\Collection;
*/
class AccountReportHelper implements AccountReportHelperInterface
{
/**
* @param Account $account
* @param Collection $startSet
* @param Collection $endSet
* @param Collection $backupSet
*
* @return Account
*/
public static function reportFilter(Account $account, Collection $startSet, Collection $endSet, Collection $backupSet)
{
// The balance for today always incorporates transactions made on today. So to get todays "start" balance, we sub one day.
$account->startBalance = '0';
$account->endBalance = '0';
$currentStart = $startSet->filter(
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
$currentBackup = $backupSet->filter( // grab entry from current backup as well:
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
// first try to set from backup
if (!is_null($currentBackup->first())) {
$account->startBalance = $currentBackup->first()->balance;
}
// overrule with data from start
if (!is_null($currentStart->first())) {
$account->startBalance = $currentStart->first()->balance;
}
$currentEnd = $endSet->filter(
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
if (!is_null($currentEnd->first())) {
$account->endBalance = $currentEnd->first()->balance;
}
return $account;
}
/**
* This method generates a full report for the given period on all
* given accounts.
@ -53,34 +101,7 @@ class AccountReportHelper implements AccountReportHelperInterface
$accounts->each(
function (Account $account) use ($startSet, $endSet, $backupSet) {
// The balance for today always incorporates transactions made on today. So to get todays "start" balance, we sub one day.
$account->startBalance = '0';
$account->endBalance = '0';
$currentStart = $startSet->filter(
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
$currentBackup = $backupSet->filter( // grab entry from current backup as well:
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
if (!is_null($currentStart->first())) {
$account->startBalance = $currentStart->first()->balance;
}
if (is_null($currentStart->first()) && !is_null($currentBackup->first())) {
$account->startBalance = $currentBackup->first()->balance;
}
$currentEnd = $endSet->filter(
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
if (!is_null($currentEnd->first())) {
$account->endBalance = $currentEnd->first()->balance;
}
return self::reportFilter($account, $startSet, $endSet, $backupSet);
}
);

View File

@ -74,7 +74,7 @@ class ReportHelper implements ReportHelperInterface
foreach ($bills as $bill) {
$billLine = new BillLine;
$billLine->setBill($bill);
$billLine->setActive(intval($bill->active) == 1);
$billLine->setActive(intval($bill->active) === 1);
$billLine->setMin($bill->amount_min);
$billLine->setMax($bill->amount_max);
$billLine->setHit(false);
@ -91,10 +91,10 @@ class ReportHelper implements ReportHelperInterface
$billLine->setAmount($first->journalAmount);
$billLine->setHit(true);
}
if (!(!$billLine->isHit() && !$billLine->isActive())) {
if ($billLine->isHitAndActive()) {
$collection->addBill($billLine);
}
}
return $collection;

View File

@ -47,9 +47,18 @@ class BudgetController extends Controller
public function amount(BudgetRepositoryInterface $repository, Budget $budget)
{
$amount = intval(Input::get('amount'));
/** @var Carbon $date */
$date = session('start', Carbon::now()->startOfMonth());
$limitRepetition = $repository->updateLimitAmount($budget, $date, $amount);
/** @var Carbon $start */
$start = session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
$viewRange = Preferences::get('viewRange', '1M')->data;
// is custom view range?
if (session('is_custom_range') === true) {
$viewRange = 'custom';
}
$limitRepetition = $repository->updateLimitAmount($budget, $start, $end, $viewRange, $amount);
if ($amount == 0) {
$limitRepetition = null;
}
@ -160,14 +169,6 @@ class BudgetController extends Controller
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
/**
* Warn user if necessary
*/
$userWarning = '';
if (session('is_custom_range', false) === true) {
$userWarning = strval(trans('firefly.warn_range_' . $repeatFreq));
}
/**
* Do some cleanup:
*/
@ -195,7 +196,7 @@ class BudgetController extends Controller
'budgetMaximum', 'periodStart', 'periodEnd',
'period', 'range', 'budgetIncomeTotal',
'defaultCurrency', 'inactive', 'budgets',
'spent', 'budgeted', 'userWarning'
'spent', 'budgeted'
)
);
}

View File

@ -3,7 +3,6 @@
namespace FireflyIII\Jobs;
use ErrorException;
use FireflyIII\User;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Message;
use Illuminate\Queue\InteractsWithQueue;
@ -27,27 +26,29 @@ class MailError extends Job implements ShouldQueue
protected $exception;
/** @var string */
protected $ipAddress;
/** @var User */
protected $user;
/** @var array */
protected $userData;
/**
* MailError constructor.
*
* @param User $user
* @param array $userData
* @param string $destination
* @param string $ipAddress
* @param array $exceptionData
*
*/
public function __construct(User $user, string $destination, string $ipAddress, array $exceptionData)
public function __construct(array $userData, string $destination, string $ipAddress, array $exceptionData)
{
$this->user = $user;
$this->userData = $userData;
$this->destination = $destination;
$this->ipAddress = $ipAddress;
$this->exception = $exceptionData;
Log::debug('In mail job constructor for error handler.');
Log::error('Exception is: ' . json_encode($exceptionData));
$debug = $exceptionData;
unset($debug['stackTrace']);
Log::error('Exception is: ' . json_encode($debug));
}
/**
@ -63,8 +64,8 @@ class MailError extends Job implements ShouldQueue
try {
$email = env('SITE_OWNER');
$args = $this->exception;
$args['loggedIn'] = !is_null($this->user->id);
$args['user'] = $this->user;
$args['loggedIn'] = $this->userData['id'] > 0;
$args['user'] = $this->userData;
$args['ip'] = $this->ipAddress;
Mail::send(

View File

@ -36,6 +36,12 @@ class EventServiceProvider extends ServiceProvider
'FireflyIII\Handlers\Events\FireRulesForUpdate',
],
'FireflyIII\Events\BudgetLimitStored' => [
'FireflyIII\Handlers\Events\BudgetLimitEventHandler@store',
],
'FireflyIII\Events\BudgetLimitUpdated' => [
'FireflyIII\Handlers\Events\BudgetLimitEventHandler@update',
],
'FireflyIII\Events\TransactionJournalStored' => [
'FireflyIII\Handlers\Events\ScanForBillsAfterStore',
'FireflyIII\Handlers\Events\ConnectJournalToPiggyBank',
@ -66,39 +72,6 @@ class EventServiceProvider extends ServiceProvider
parent::boot($events);
$this->registerDeleteEvents();
$this->registerCreateEvents();
BudgetLimit::saved(
function (BudgetLimit $budgetLimit) {
$end = Navigation::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0);
$end->subDay();
$set = $budgetLimit->limitrepetitions()
->where('startdate', $budgetLimit->startdate->format('Y-m-d 00:00:00'))
->where('enddate', $end->format('Y-m-d 00:00:00'))
->get();
if ($set->count() == 0) {
$repetition = new LimitRepetition;
$repetition->startdate = $budgetLimit->startdate;
$repetition->enddate = $end;
$repetition->amount = $budgetLimit->amount;
$repetition->budgetLimit()->associate($budgetLimit);
try {
$repetition->save();
} catch (QueryException $e) {
Log::error('Trying to save new LimitRepetition failed: ' . $e->getMessage());
}
}
if ($set->count() == 1) {
$repetition = $set->first();
$repetition->amount = $budgetLimit->amount;
$repetition->save();
}
}
);
//
}
/**

View File

@ -5,6 +5,8 @@ namespace FireflyIII\Repositories\Budget;
use Carbon\Carbon;
use DB;
use FireflyIII\Events\BudgetLimitStored;
use FireflyIII\Events\BudgetLimitUpdated;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
@ -19,7 +21,6 @@ use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Input;
use Preferences;
/**
* Class BudgetRepository
@ -859,43 +860,54 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
/**
* @param Budget $budget
* @param Carbon $date
* @param Carbon $start
* @param Carbon $end
* @param string $range
* @param int $amount
*
* @return BudgetLimit
*/
public function updateLimitAmount(Budget $budget, Carbon $date, int $amount): BudgetLimit
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount) : BudgetLimit
{
// there might be a budget limit for this startdate:
$viewRange = Preferences::get('viewRange', '1M')->data;
$repeatFreq = config('firefly.range_to_repeat_freq.' . $viewRange);
$repeatFreq = config('firefly.range_to_repeat_freq.' . $range);
/** @var BudgetLimit $limit */
$limit = $budget->budgetlimits()->where('budget_limits.startdate', $date)->where('budget_limits.repeat_freq', $repeatFreq)->first(['budget_limits.*']);
$limit = $budget->budgetlimits()
->where('budget_limits.startdate', $start)
->where('budget_limits.repeat_freq', $repeatFreq)->first(['budget_limits.*']);
if (!$limit) {
// if not, create one!
$limit = new BudgetLimit;
$limit->budget()->associate($budget);
$limit->startdate = $date;
$limit->amount = $amount;
$limit->repeat_freq = $repeatFreq;
$limit->repeats = 0;
// delete if amount is zero.
if (!is_null($limit) && $amount <= 0.0) {
$limit->delete();
return new BudgetLimit;
}
// update if exists:
if (!is_null($limit)) {
$limit->amount = $amount;
$limit->save();
// likewise, there should be a limit repetition to match the end date
// (which is always the end of the month) but that is caught by an event.
// so handled automatically.
// fire event to create or update LimitRepetition.
event(new BudgetLimitUpdated($limit, $end));
} else {
if ($amount > 0) {
$limit->amount = $amount;
$limit->save();
} else {
$limit->delete();
}
return $limit;
}
// create one and return it.
$limit = new BudgetLimit;
$limit->budget()->associate($budget);
$limit->startdate = $start;
$limit->amount = $amount;
$limit->repeat_freq = $repeatFreq;
$limit->repeats = 0;
$limit->save();
event(new BudgetLimitStored($limit, $end));
// likewise, there should be a limit repetition to match the end date
// (which is always the end of the month) but that is caught by an event.
// so handled automatically.
return $limit;
}
}

View File

@ -309,11 +309,13 @@ interface BudgetRepositoryInterface
/**
* @param Budget $budget
* @param Carbon $date
* @param Carbon $start
* @param Carbon $end
* @param string $range
* @param int $amount
*
* @return BudgetLimit
*/
public function updateLimitAmount(Budget $budget, Carbon $date, int $amount) : BudgetLimit;
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount) : BudgetLimit;
}

View File

@ -12,6 +12,7 @@ namespace FireflyIII\Support\Migration;
use Carbon\Carbon;
use Crypt;
use FireflyIII\Events\BudgetLimitStored;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\Attachment;
@ -30,6 +31,7 @@ use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\User;
use Navigation;
use Storage;
/**
@ -209,6 +211,10 @@ class TestData
'repeat_freq' => 'monthly',
]
);
// also trigger event.
$thisEnd = Navigation::addPeriod($start, 'monthly', 0);
$thisEnd->subDay();
event(new BudgetLimitStored($limit, $thisEnd));
return $limit;
}

View File

@ -50,7 +50,6 @@ class Steam
*
* @param \FireflyIII\Models\Account $account
* @param \Carbon\Carbon $date
* @param bool $ignoreVirtualBalance
*
* @return string
*/

View File

@ -64,7 +64,7 @@ return [
'3M' => 'quarterly',
'6M' => 'half-year',
'1Y' => 'yearly',
'custom' => 'monthly',
'custom' => 'custom',
],
'subTitlesByIdentifier' =>
[

View File

@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class ChangesFor385 extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// remove an index.
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropUnique('unique_limit');
}
);
// create it again, correctly.
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->unique(['budget_id', 'startdate','repeat_freq'], 'unique_limit');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -0,0 +1,148 @@
<?php
use FireflyIII\Models\BudgetLimit;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class ChangesForV385
*/
class ChangesForV385 extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$backup = $this->backupRepeatFreqsFromString();
// drop string and create enum field
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropColumn('repeat_freq');
}
);
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']);
}
);
// restore backup. Change unknowns to "monthly".
$this->restoreRepeatFreqsToEnum($backup);
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// remove an index.
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropUnique('unique_limit');
$table->dropForeign('bid_foreign');
$table->dropUnique('unique_bl_combi');
}
);
// recreate foreign key:
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->foreign('budget_id', 'bid_foreign')->references('id')->on('budgets')->onDelete('cascade');
}
);
// backup values
$backup = $this->backupRepeatFreqsFromEnum();
// drop enum and create varchar field
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropColumn('repeat_freq');
}
);
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->string('repeat_freq', 20)->default('monthly');
}
);
// put data back:
$this->restoreRepeatFreqsToVarchar($backup);
// create it again, correctly.
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->unique(['budget_id', 'startdate', 'repeat_freq'], 'unique_limit');
}
);
}
/**
* @return array
*/
private function backupRepeatFreqsFromEnum(): array
{
$backup = [];
$set = BudgetLimit::get();
/** @var BudgetLimit $entry */
foreach ($set as $entry) {
$backup[$entry->id] = $entry->repeat_freq;
}
return $backup;
}
/**
* Same routine.
*
* @return array
*/
private function backupRepeatFreqsFromString()
{
return $this->backupRepeatFreqsFromEnum();
}
/**
* @param array $backup
*
* @return bool
*/
private function restoreRepeatFreqsToEnum(array $backup): bool
{
foreach ($backup as $id => $repeatFreq) {
$budgetLimit = BudgetLimit::find($id);
if (!in_array($repeatFreq, ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'])) {
$repeatFreq = 'monthly';
}
$budgetLimit->repeat_freq = $repeatFreq;
$budgetLimit->save();
}
return true;
}
/**
* @param array $backup
*
* @return bool
*/
private function restoreRepeatFreqsToVarchar(array $backup): bool
{
foreach ($backup as $id => $repeatFreq) {
$budgetLimit = BudgetLimit::find($id);
$budgetLimit->repeat_freq = $repeatFreq;
$budgetLimit->save();
}
return true;
}
}

View File

@ -9,6 +9,7 @@ declare(strict_types = 1);
*/
use Carbon\Carbon;
use FireflyIII\Events\BudgetLimitStored;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Support\Migration\TestData;
use Illuminate\Database\Seeder;
@ -94,19 +95,24 @@ class TestDataSeeder extends Seeder
// create some special budget limits to test stuff with multiple budget limits
// for a range of dates:
$this->end->startOfMonth();
$this->end->startOfMonth()->addDay();
$budget = TestData::findBudget($user, 'Bills');
$ranges = ['daily','weekly','monthly','quarterly','half-year','yearly'];
foreach($ranges as $range) {
BudgetLimit::create(
$ranges = ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'];
foreach ($ranges as $range) {
$limit = BudgetLimit::create(
[
'budget_id' => $budget->id,
'startdate' => $this->end->format('Y-m-d'),
'amount' => rand(100,200),
'amount' => rand(100, 200),
'repeats' => 0,
'repeat_freq' => $range,
]
);
// also trigger event.
$thisEnd = Navigation::addPeriod($this->end, $range, 0);
$thisEnd->subDay();
event(new BudgetLimitStored($limit, $thisEnd));
$this->end->addDay();
}

View File

@ -477,12 +477,6 @@ return [
'update_amount' => 'Update amount',
'update_budget' => 'Update budget',
'update_budget_amount_range' => 'Update (expected) available amount between :start and :end',
'warn_range_weekly' => 'You have selected a custom date range using the top right date range selection tool. Your preferences indicate you prefer a "weekly" view. Changes to the budgets below will be valid for exactly one week from now.',
'warn_range_monthly' => 'You have selected a custom date range using the top right date range selection tool. Your preferences indicate you prefer a "monthly" view. Changes to the budgets below will be valid for exactly one month from now.',
'warn_range_quarterly' => 'You have selected a custom date range using the top right date range selection tool. Your preferences indicate you prefer a "quarter" view. Changes to the budgets below will be valid for exactly three months from now.',
'warn_range_half-year' => 'You have selected a custom date range using the top right date range selection tool. Your preferences indicate you prefer the "six months" overview. Changes to the budgets below will be valid for exactly six months from now.',
'warn_range_custom' => 'You have selected a custom date range using the top right date range selection tool. Your preferences indicate you prefer a custom range. Changes to the budgets below will be valid for your custom range.',
'warn_range_yearly' => 'You have selected a custom date range using the top right date range selection tool. Your preferences indicate you prefer the "yearly" overview. Changes to the budgets below will be valid for exactly one year from now.',
// bills:
'matching_on' => 'Matching on',

View File

@ -99,19 +99,6 @@
</div>
</div>
{% if userWarning != "" %}
<div class="row">
<div class="col-lg-12">
<p class="well">
<span class="text-danger">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i>
{{ userWarning }}
</span>
</p>
</div>
</div>
{% endif %}
<div class="row">
{% for budget in budgets %}
<div class="col-lg-4 col-sm-6 col-md-6">