mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-13 16:00:13 +00:00
Code for issue #489
This commit is contained in:
@@ -15,10 +15,10 @@ namespace FireflyIII\Http\Controllers;
|
|||||||
|
|
||||||
use Amount;
|
use Amount;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Config;
|
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||||
|
use FireflyIII\Http\Requests\BudgetIncomeRequest;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
@@ -26,8 +26,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Input;
|
use Input;
|
||||||
use Log;
|
|
||||||
use Navigation;
|
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Response;
|
use Response;
|
||||||
use Session;
|
use Session;
|
||||||
@@ -42,6 +40,9 @@ use View;
|
|||||||
class BudgetController extends Controller
|
class BudgetController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var BudgetRepositoryInterface */
|
||||||
|
private $repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -55,6 +56,7 @@ class BudgetController extends Controller
|
|||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
View::share('title', trans('firefly.budgets'));
|
View::share('title', trans('firefly.budgets'));
|
||||||
View::share('mainTitleIcon', 'fa-tasks');
|
View::share('mainTitleIcon', 'fa-tasks');
|
||||||
|
$this->repository = app(BudgetRepositoryInterface::class);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@@ -73,14 +75,8 @@ class BudgetController extends Controller
|
|||||||
/** @var Carbon $start */
|
/** @var Carbon $start */
|
||||||
$start = session('start', Carbon::now()->startOfMonth());
|
$start = session('start', Carbon::now()->startOfMonth());
|
||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = session('end', Carbon::now()->endOfMonth());
|
$end = session('end', Carbon::now()->endOfMonth());
|
||||||
$viewRange = Preferences::get('viewRange', '1M')->data;
|
$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);
|
$limitRepetition = $repository->updateLimitAmount($budget, $start, $end, $viewRange, $amount);
|
||||||
if ($amount == 0) {
|
if ($amount == 0) {
|
||||||
$limitRepetition = null;
|
$limitRepetition = null;
|
||||||
@@ -173,82 +169,27 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param BudgetRepositoryInterface $repository
|
|
||||||
* @param AccountRepositoryInterface $accountRepository
|
|
||||||
*
|
|
||||||
* @return View
|
* @return View
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function index(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
public function index()
|
||||||
{
|
{
|
||||||
$repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
|
||||||
$budgets = $repository->getActiveBudgets();
|
$budgets = $this->repository->getActiveBudgets();
|
||||||
$inactive = $repository->getInactiveBudgets();
|
$inactive = $this->repository->getInactiveBudgets();
|
||||||
$spent = '0';
|
$start = session('start', new Carbon);
|
||||||
$budgeted = '0';
|
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
|
||||||
$repeatFreq = Config::get('firefly.range_to_repeat_freq.' . $range);
|
|
||||||
|
|
||||||
if (session('is_custom_range') === true) {
|
|
||||||
$repeatFreq = 'custom';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var Carbon $start */
|
|
||||||
$start = session('start', new Carbon);
|
|
||||||
/** @var Carbon $end */
|
|
||||||
$end = session('end', new Carbon);
|
$end = session('end', new Carbon);
|
||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
|
||||||
$budgetIncomeTotal = Preferences::get($key, 1000)->data;
|
|
||||||
$period = Navigation::periodShow($start, $range);
|
|
||||||
$periodStart = $start->formatLocalized($this->monthAndDayFormat);
|
$periodStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||||
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
|
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
|
$budgetInformation = $this->collectBudgetInformation($budgets, $start, $end);
|
||||||
$startAsString = $start->format('Y-m-d');
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
$endAsString = $end->format('Y-m-d');
|
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||||
Log::debug('Now at /budgets');
|
$spent = array_sum(array_column($budgetInformation, 'spent'));
|
||||||
|
$budgeted = array_sum(array_column($budgetInformation, 'budgeted'));
|
||||||
// loop the budgets:
|
|
||||||
/** @var Budget $budget */
|
|
||||||
foreach ($budgets as $budget) {
|
|
||||||
Log::debug(sprintf('Now at budget #%d ("%s")', $budget->id, $budget->name));
|
|
||||||
$budget->spent = $repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
|
|
||||||
$allRepetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
|
|
||||||
$otherRepetitions = new Collection;
|
|
||||||
|
|
||||||
/** @var LimitRepetition $repetition */
|
|
||||||
foreach ($allRepetitions as $repetition) {
|
|
||||||
if ($repetition->budget_id == $budget->id) {
|
|
||||||
if ($repetition->budgetLimit->repeat_freq == $repeatFreq
|
|
||||||
&& $repetition->startdate->format('Y-m-d') == $startAsString
|
|
||||||
&& $repetition->enddate->format('Y-m-d') == $endAsString
|
|
||||||
) {
|
|
||||||
// do something
|
|
||||||
$budget->currentRep = $repetition;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$otherRepetitions->push($repetition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$budget->otherRepetitions = $otherRepetitions;
|
|
||||||
|
|
||||||
if (!is_null($budget->currentRep) && !is_null($budget->currentRep->id)) {
|
|
||||||
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
|
|
||||||
}
|
|
||||||
$spent = bcadd($spent, $budget->spent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$defaultCurrency = Amount::getDefaultCurrency();
|
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'budgets.index', compact(
|
'budgets.index',
|
||||||
'periodStart', 'periodEnd',
|
compact('available', 'periodStart', 'periodEnd', 'budgetInformation', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
|
||||||
'period', 'range', 'budgetIncomeTotal',
|
|
||||||
'defaultCurrency', 'inactive', 'budgets',
|
|
||||||
'spent', 'budgeted'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,16 +221,14 @@ class BudgetController extends Controller
|
|||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function postUpdateIncome()
|
public function postUpdateIncome(BudgetIncomeRequest $request)
|
||||||
{
|
{
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
$start = session('start', new Carbon);
|
||||||
/** @var Carbon $date */
|
$end = session('end', new Carbon);
|
||||||
$date = session('start', new Carbon);
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
$start = Navigation::startOfPeriod($date, $range);
|
$amount = $request->get('amount');
|
||||||
$end = Navigation::endOfPeriod($start, $range);
|
|
||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
|
||||||
|
|
||||||
Preferences::set($key, intval(Input::get('amount')));
|
$this->repository->setAvailableBudget($defaultCurrency, $start, $end, $amount);
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return redirect(route('budgets.index'));
|
return redirect(route('budgets.index'));
|
||||||
@@ -430,19 +369,57 @@ class BudgetController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function updateIncome()
|
public function updateIncome()
|
||||||
{
|
{
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
$start = session('start', new Carbon);
|
||||||
$format = strval(trans('config.month_and_day'));
|
$end = session('end', new Carbon);
|
||||||
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
|
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||||
|
|
||||||
/** @var Carbon $date */
|
|
||||||
$date = session('start', new Carbon);
|
|
||||||
$start = Navigation::startOfPeriod($date, $range);
|
|
||||||
$end = Navigation::endOfPeriod($start, $range);
|
|
||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
|
||||||
$amount = Preferences::get($key, 1000);
|
|
||||||
$displayStart = $start->formatLocalized($format);
|
|
||||||
$displayEnd = $end->formatLocalized($format);
|
|
||||||
|
|
||||||
return view('budgets.income', compact('amount', 'displayStart', 'displayEnd'));
|
return view('budgets.income', compact('available', 'start', 'end'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function collectBudgetInformation(Collection $budgets, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
// get account information
|
||||||
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
|
||||||
|
$return = [];
|
||||||
|
/** @var Budget $budget */
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$budgetId = $budget->id;
|
||||||
|
$return[$budgetId] = [
|
||||||
|
'spent' => $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end),
|
||||||
|
'budgeted' => '0',
|
||||||
|
'currentRep' => false,
|
||||||
|
];
|
||||||
|
$allRepetitions = $this->repository->getAllBudgetLimitRepetitions($start, $end);
|
||||||
|
$otherRepetitions = new Collection;
|
||||||
|
|
||||||
|
// get all the limit repetitions relevant between start and end and examine them:
|
||||||
|
/** @var LimitRepetition $repetition */
|
||||||
|
foreach ($allRepetitions as $repetition) {
|
||||||
|
if ($repetition->budget_id == $budget->id) {
|
||||||
|
if ($repetition->startdate->isSameDay($start) && $repetition->enddate->isSameDay($end)
|
||||||
|
) {
|
||||||
|
$return[$budgetId]['currentRep'] = $repetition;
|
||||||
|
$return[$budgetId]['budgeted'] = $repetition->amount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// otherwise it's just one of the many relevant repetitions:
|
||||||
|
$otherRepetitions->push($repetition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$return[$budgetId]['otherRepetitions'] = $otherRepetitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -63,6 +63,7 @@ class HomeController extends Controller
|
|||||||
// a possible problem with the budgets.
|
// a possible problem with the budgets.
|
||||||
if ($label === strval(trans('firefly.everything')) || $label === strval(trans('firefly.customRange'))) {
|
if ($label === strval(trans('firefly.everything')) || $label === strval(trans('firefly.customRange'))) {
|
||||||
$isCustomRange = true;
|
$isCustomRange = true;
|
||||||
|
Preferences::set('viewRange', 'custom');
|
||||||
Log::debug('Range is now marked as "custom".');
|
Log::debug('Range is now marked as "custom".');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
app/Http/Requests/BudgetIncomeRequest.php
Normal file
42
app/Http/Requests/BudgetIncomeRequest.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetIncomeRequest.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Requests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BudgetIncomeRequest
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Requests
|
||||||
|
*/
|
||||||
|
class BudgetIncomeRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
// Only allow logged in users
|
||||||
|
return auth()->check();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'amount' => 'numeric|required|min:0',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
49
app/Models/AvailableBudget.php
Normal file
49
app/Models/AvailableBudget.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AvailableBudget.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Models;
|
||||||
|
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AvailableBudget
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Models
|
||||||
|
*/
|
||||||
|
class AvailableBudget extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
/** @var array */
|
||||||
|
protected $dates = ['created_at', 'updated_at', 'deleted_at', 'start_date', 'end_date'];
|
||||||
|
/** @var array */
|
||||||
|
protected $fillable = ['user_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function transactionCurrency()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('FireflyIII\Models\TransactionCurrency');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BelongsTo
|
||||||
|
*/
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo('FireflyIII\User');
|
||||||
|
}
|
||||||
|
}
|
@@ -17,10 +17,12 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Events\StoredBudgetLimit;
|
use FireflyIII\Events\StoredBudgetLimit;
|
||||||
use FireflyIII\Events\UpdatedBudgetLimit;
|
use FireflyIII\Events\UpdatedBudgetLimit;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
|
use FireflyIII\Models\AvailableBudget;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
@@ -210,6 +212,27 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string
|
||||||
|
{
|
||||||
|
$amount = '0';
|
||||||
|
$availableBudget = $this->user->availableBudgets()
|
||||||
|
->where('transaction_currency_id', $currency->id)
|
||||||
|
->where('start_date', $start->format('Y-m-d'))
|
||||||
|
->where('end_date', $end->format('Y-m-d'))->first();
|
||||||
|
if (!is_null($availableBudget)) {
|
||||||
|
$amount = strval($availableBudget->amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $amount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is being used to generate the budget overview in the year/multi-year report. Its used
|
* This method is being used to generate the budget overview in the year/multi-year report. Its used
|
||||||
* in both the year/multi-year budget overview AND in the accompanying chart.
|
* in both the year/multi-year budget overview AND in the accompanying chart.
|
||||||
@@ -322,6 +345,33 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $amount
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): bool
|
||||||
|
{
|
||||||
|
$availableBudget = $this->user->availableBudgets()
|
||||||
|
->where('transaction_currency_id', $currency->id)
|
||||||
|
->where('start_date', $start->format('Y-m-d'))
|
||||||
|
->where('end_date', $end->format('Y-m-d'))->first();
|
||||||
|
if (is_null($availableBudget)) {
|
||||||
|
$availableBudget = new AvailableBudget;
|
||||||
|
$availableBudget->user()->associate($this->user);
|
||||||
|
$availableBudget->transactionCurrency()->associate($currency);
|
||||||
|
$availableBudget->start_date = $start;
|
||||||
|
$availableBudget->end_date = $end;
|
||||||
|
}
|
||||||
|
$availableBudget->amount = $amount;
|
||||||
|
$availableBudget->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $budgets
|
* @param Collection $budgets
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
|
@@ -16,6 +16,7 @@ namespace FireflyIII\Repositories\Budget;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +91,15 @@ interface BudgetRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end): Collection;
|
public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param Collection $budgets
|
* @param Collection $budgets
|
||||||
@@ -120,6 +130,16 @@ interface BudgetRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array;
|
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $amount
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $budgets
|
* @param Collection $budgets
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
|
@@ -51,6 +51,15 @@ class User extends Authenticatable
|
|||||||
*/
|
*/
|
||||||
protected $table = 'users';
|
protected $table = 'users';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return HasMany
|
||||||
|
*/
|
||||||
|
public function availableBudgets(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany('FireflyIII\Models\AvailableBudget');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany
|
* @return HasMany
|
||||||
*/
|
*/
|
||||||
|
44
database/migrations/2016_12_22_150431_changes_for_v430.php
Normal file
44
database/migrations/2016_12_22_150431_changes_for_v430.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChangesForV430
|
||||||
|
*/
|
||||||
|
class ChangesForV430 extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('available_budgets', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
$table->integer('user_id', false, true);
|
||||||
|
$table->integer('transaction_currency_id', false, true);
|
||||||
|
$table->decimal('amount', 14, 4);
|
||||||
|
$table->date('start_date');
|
||||||
|
$table->date('end_date');
|
||||||
|
|
||||||
|
|
||||||
|
$table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade');
|
||||||
|
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('available_budgets');
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,3 @@
|
|||||||
/* globals $, budgeted:true, currencySymbol, budgetIncomeTotal, columnChart, budgetedMuch, budgetedPercentage, token, budgetID, repetitionID, spent, lineChart */
|
|
||||||
|
|
||||||
function drawSpentBar() {
|
function drawSpentBar() {
|
||||||
"use strict";
|
"use strict";
|
||||||
if ($('.spentBar').length > 0) {
|
if ($('.spentBar').length > 0) {
|
||||||
@@ -23,19 +21,19 @@ function drawBudgetedBar() {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
if ($('.budgetedBar').length > 0) {
|
if ($('.budgetedBar').length > 0) {
|
||||||
var budgetedMuch = budgeted > budgetIncomeTotal;
|
var budgetedMuch = budgeted > available;
|
||||||
|
|
||||||
// recalculate percentage:
|
// recalculate percentage:
|
||||||
|
|
||||||
var pct;
|
var pct;
|
||||||
if (budgetedMuch) {
|
if (budgetedMuch) {
|
||||||
// budgeted too much.
|
// budgeted too much.
|
||||||
pct = (budgetIncomeTotal / budgeted) * 100;
|
pct = (available / budgeted) * 100;
|
||||||
$('.budgetedBar .progress-bar-warning').css('width', pct + '%');
|
$('.budgetedBar .progress-bar-warning').css('width', pct + '%');
|
||||||
$('.budgetedBar .progress-bar-danger').css('width', (100 - pct) + '%');
|
$('.budgetedBar .progress-bar-danger').css('width', (100 - pct) + '%');
|
||||||
$('.budgetedBar .progress-bar-info').css('width', 0);
|
$('.budgetedBar .progress-bar-info').css('width', 0);
|
||||||
} else {
|
} else {
|
||||||
pct = (budgeted / budgetIncomeTotal) * 100;
|
pct = (budgeted / available) * 100;
|
||||||
$('.budgetedBar .progress-bar-warning').css('width', 0);
|
$('.budgetedBar .progress-bar-warning').css('width', 0);
|
||||||
$('.budgetedBar .progress-bar-danger').css('width', 0);
|
$('.budgetedBar .progress-bar-danger').css('width', 0);
|
||||||
$('.budgetedBar .progress-bar-info').css('width', pct + '%');
|
$('.budgetedBar .progress-bar-info').css('width', pct + '%');
|
||||||
|
@@ -4,7 +4,8 @@
|
|||||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">{{ 'close'|_ }}</span>
|
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">{{ 'close'|_ }}</span>
|
||||||
</button>
|
</button>
|
||||||
<h4 class="modal-title" id="myModalLabel">
|
<h4 class="modal-title" id="myModalLabel">
|
||||||
{{ trans('firefly.update_budget_amount_range', {start: displayStart, end: displayEnd}) }}
|
{{ trans('firefly.update_budget_amount_range',
|
||||||
|
{start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat)}) }}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">{{ getCurrencySymbol()|raw }}</div>
|
<div class="input-group-addon">{{ getCurrencySymbol()|raw }}</div>
|
||||||
<input step="any" class="form-control" id="amount" value="{{ amount.data }}" autocomplete="off" name="amount" type="number"/>
|
<input step="any" class="form-control" id="amount" value="{{ available }}" autocomplete="off" name="amount" type="number"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
@@ -18,8 +18,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
|
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
|
||||||
<small>{{ trans('firefly.available_between',{start : periodStart, end: periodEnd }) }}:
|
<small>{{ trans('firefly.available_between',{start : periodStart, end: periodEnd }) }}:
|
||||||
<a href="#" class="updateIncome"><span id="budgetIncomeTotal"
|
<a href="#" class="updateIncome"><span id="available"
|
||||||
data-value="{{ budgetIncomeTotal }}">{{ budgetIncomeTotal|formatAmount }}</span></a>
|
data-value="{{ available }}">{{ available|formatAmountPlain }}</span></a>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,8 +90,8 @@
|
|||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">
|
<h3 class="box-title">
|
||||||
<!-- link in header -->
|
<!-- link in header -->
|
||||||
{% if budget.currentRep.id %}
|
{% if budgetInformation[budget.id]['currentRep'] %}
|
||||||
<a href="{{ route('budgets.show.repetition', [budget.id, budget.currentRep.id]) }}" class="budget-link"
|
<a href="{{ route('budgets.show.repetition', [budget.id, budgetInformation[budget.id]['currentRep'].id]) }}" class="budget-link"
|
||||||
data-id="{{ budget.id }}">{{ budget.name }}</a>
|
data-id="{{ budget.id }}">{{ budget.name }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ route('budgets.show',budget.id) }}" class="budget-link" data-id="{{ budget.id }}">{{ budget.name }}</a>
|
<a href="{{ route('budgets.show',budget.id) }}" class="budget-link" data-id="{{ budget.id }}">{{ budget.name }}</a>
|
||||||
@@ -122,20 +122,16 @@
|
|||||||
<div class="form-group" style="margin-bottom:0;">
|
<div class="form-group" style="margin-bottom:0;">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon">{{ defaultCurrency.symbol|raw }}</div>
|
<div class="input-group-addon">{{ defaultCurrency.symbol|raw }}</div>
|
||||||
<input type="hidden" name="balance_currency_id" value="1"/>
|
<input type="hidden" name="balance_currency_id" value="{{ defaultCurrency.id }}"/>
|
||||||
<input class="form-control budgetAmount" data-original="{{ budget.currentRep.amount|number_format(0,'','') }}"
|
{% if budgetInformation[budget.id]['currentRep'] %}
|
||||||
data-id="{{ budget.id }}" value="{{ budget.currentRep.amount|number_format(0,'','') }}" autocomplete="off"
|
{% set repAmount = budgetInformation[budget.id]['currentRep'].amount %}
|
||||||
|
{% else %}
|
||||||
|
{% set repAmount = '0' %}
|
||||||
|
{% endif %}
|
||||||
|
<input class="form-control budgetAmount" data-original="{{ repAmount }}"
|
||||||
|
data-id="{{ budget.id }}" value="{{ repAmount }}" autocomplete="off"
|
||||||
step="1" min="0" name="amount" type="number">
|
step="1" min="0" name="amount" type="number">
|
||||||
</div>
|
</div>
|
||||||
<!--
|
|
||||||
<div class="small">
|
|
||||||
<ul class="list-inline">
|
|
||||||
<li>Previously budgeted:</li>
|
|
||||||
<li><a href="#">{{ 123|formatAmountPlain }}</a></li>
|
|
||||||
<li><a href="#">{{ 456|formatAmountPlain }}</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -147,21 +143,23 @@
|
|||||||
{{ session('end').formatLocalized(monthAndDayFormat) }}
|
{{ session('end').formatLocalized(monthAndDayFormat) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ budget.spent|formatAmount }}</a></td>
|
<td>
|
||||||
|
{{ budgetInformation[budget.id]['spent']|formatAmount }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if budget.otherRepetitions.count > 0 %}
|
{% if budgetInformation[budget.id]['otherRepetitions'].count > 0 %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
{% for other in budget.otherRepetitions %}
|
{% for other in budgetInformation[budget.id]['otherRepetitions'] %}
|
||||||
{% if other.id != budget.currentRep.id %}
|
<li>
|
||||||
<li>Budgeted
|
<!-- translate -->
|
||||||
<a href="{{ route('budgets.show.repetition', [budget.id, other.id]) }}">{{ other.amount|formatAmountPlain }}</a>
|
Budgeted
|
||||||
between
|
<a href="{{ route('budgets.show.repetition', [budget.id, other.id]) }}">{{ other.amount|formatAmountPlain }}</a>
|
||||||
{{ other.startdate.formatLocalized(monthAndDayFormat) }}
|
between
|
||||||
and {{ other.enddate.formatLocalized(monthAndDayFormat) }}.
|
{{ other.startdate.formatLocalized(monthAndDayFormat) }}
|
||||||
</li>
|
and {{ other.enddate.formatLocalized(monthAndDayFormat) }}.
|
||||||
{% endif %}
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
@@ -206,7 +204,7 @@
|
|||||||
|
|
||||||
// budgeted data:
|
// budgeted data:
|
||||||
var budgeted = {{ budgeted }};
|
var budgeted = {{ budgeted }};
|
||||||
var budgetIncomeTotal = {{ budgetIncomeTotal }};
|
var available = {{ available }};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript" src="js/ff/budgets/index.js"></script>
|
<script type="text/javascript" src="js/ff/budgets/index.js"></script>
|
||||||
|
Reference in New Issue
Block a user