mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-30 02:26:58 +00:00
Allow user to set multi-currency available budget. WIP
This commit is contained in:
@@ -24,15 +24,23 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Http\Controllers\Budget;
|
namespace FireflyIII\Http\Controllers\Budget;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\Models\AvailableBudget;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -40,6 +48,7 @@ use Illuminate\Http\Request;
|
|||||||
*/
|
*/
|
||||||
class BudgetLimitController extends Controller
|
class BudgetLimitController extends Controller
|
||||||
{
|
{
|
||||||
|
use DateCalculation;
|
||||||
|
|
||||||
/** @var AvailableBudgetRepositoryInterface */
|
/** @var AvailableBudgetRepositoryInterface */
|
||||||
private $abRepository;
|
private $abRepository;
|
||||||
@@ -73,6 +82,35 @@ class BudgetLimitController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
|
*/
|
||||||
|
public function create(Budget $budget, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$collection = $this->currencyRepos->getEnabled();
|
||||||
|
$budgetLimits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||||
|
|
||||||
|
// remove already budgeted currencies:
|
||||||
|
$currencies = $collection->filter(
|
||||||
|
static function (TransactionCurrency $currency) use ($budgetLimits) {
|
||||||
|
/** @var AvailableBudget $budget */
|
||||||
|
foreach ($budgetLimits as $budget) {
|
||||||
|
if ($budget->transaction_currency_id === $currency->id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return view('budgets.budget-limits.create', compact('start', 'end', 'currencies', 'budget'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param BudgetLimit $budgetLimit
|
* @param BudgetLimit $budgetLimit
|
||||||
@@ -90,21 +128,62 @@ class BudgetLimitController extends Controller
|
|||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return JsonResponse
|
* @return JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function store(Request $request): JsonResponse
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$limit = $this->blRepository->store(
|
// first search for existing one and update it if necessary.
|
||||||
[
|
$currency = $this->currencyRepos->find((int)$request->get('transaction_currency_id'));
|
||||||
'budget_id' => $request->get('budget_id'),
|
$budget = $this->repository->findNull((int)$request->get('budget_id'));
|
||||||
'transaction_currency_id' => $request->get('transaction_currency_id'),
|
if (null === $currency || null === $budget) {
|
||||||
'start_date' => $request->get('start'),
|
throw new FireflyException('No valid currency or budget.');
|
||||||
'end_date' => $request->get('end'),
|
}
|
||||||
'amount' => $request->get('amount'),
|
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
|
||||||
]
|
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
|
||||||
);
|
$start->startOfDay();
|
||||||
|
$end->endOfDay();
|
||||||
|
|
||||||
return response()->json($limit->toArray());
|
|
||||||
|
Log::debug(sprintf('Start: %s, end: %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
|
$limit = $this->blRepository->find($budget, $currency, $start, $end);
|
||||||
|
if (null !== $limit) {
|
||||||
|
$limit->amount = $request->get('amount');
|
||||||
|
$limit->save();
|
||||||
|
}
|
||||||
|
if (null === $limit) {
|
||||||
|
$limit = $this->blRepository->store(
|
||||||
|
[
|
||||||
|
'budget_id' => $request->get('budget_id'),
|
||||||
|
'transaction_currency_id' => $request->get('transaction_currency_id'),
|
||||||
|
'start_date' => $request->get('start'),
|
||||||
|
'end_date' => $request->get('end'),
|
||||||
|
'amount' => $request->get('amount'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
$array = $limit->toArray();
|
||||||
|
|
||||||
|
|
||||||
|
// add some extra meta data:
|
||||||
|
$spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection([$budget]), $currency);
|
||||||
|
$array['spent'] = $spentArr[$currency->id]['sum'] ?? '0';
|
||||||
|
$array['left_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, bcadd($array['spent'], $array['amount']));
|
||||||
|
$array['amount_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $limit['amount']);
|
||||||
|
$array['days_left'] = (string)$this->activeDaysLeft($start, $end);
|
||||||
|
// left per day:
|
||||||
|
$array['left_per_day'] = bcdiv(bcadd($array['spent'], $array['amount']), $array['days_left']);
|
||||||
|
|
||||||
|
// left per day formatted.
|
||||||
|
$array['left_per_day_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $array['left_per_day']);
|
||||||
|
|
||||||
|
return response()->json($array);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect(route('budgets.index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -149,6 +149,7 @@ class IndexController extends Controller
|
|||||||
// number of days for consistent budgeting.
|
// number of days for consistent budgeting.
|
||||||
$activeDaysPassed = $this->activeDaysPassed($start, $end); // see method description.
|
$activeDaysPassed = $this->activeDaysPassed($start, $end); // see method description.
|
||||||
$activeDaysLeft = $this->activeDaysLeft($start, $end); // see method description.
|
$activeDaysLeft = $this->activeDaysLeft($start, $end); // see method description.
|
||||||
|
Log::debug(sprintf('Start: %s, end: %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// get all budgets, and paginate them into $budgets.
|
// get all budgets, and paginate them into $budgets.
|
||||||
$collection = $this->repository->getActiveBudgets();
|
$collection = $this->repository->getActiveBudgets();
|
||||||
@@ -221,18 +222,14 @@ class IndexController extends Controller
|
|||||||
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
|
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
|
||||||
{
|
{
|
||||||
$budgetIds = $request->get('budgetIds');
|
$budgetIds = $request->get('budgetIds');
|
||||||
$page = (int)$request->get('page');
|
|
||||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
|
||||||
|
|
||||||
$currentOrder = (($page - 1) * $pageSize) + 1;
|
foreach ($budgetIds as $index => $budgetId) {
|
||||||
foreach ($budgetIds as $budgetId) {
|
|
||||||
$budgetId = (int)$budgetId;
|
$budgetId = (int)$budgetId;
|
||||||
$budget = $repository->findNull($budgetId);
|
$budget = $repository->findNull($budgetId);
|
||||||
if (null !== $budget) {
|
if (null !== $budget) {
|
||||||
Log::debug(sprintf('Set budget #%d ("%s") to position %d', $budget->id, $budget->name, $currentOrder));
|
Log::debug(sprintf('Set budget #%d ("%s") to position %d', $budget->id, $budget->name, $index + 1));
|
||||||
$repository->setBudgetOrder($budget, $currentOrder);
|
$repository->setBudgetOrder($budget, $index + 1);
|
||||||
}
|
}
|
||||||
$currentOrder++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(['OK']);
|
return response()->json(['OK']);
|
||||||
|
@@ -99,6 +99,22 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return BudgetLimit|null
|
||||||
|
*/
|
||||||
|
public function find(Budget $budget, TransactionCurrency $currency, Carbon $start, Carbon $end): ?BudgetLimit
|
||||||
|
{
|
||||||
|
return $budget->budgetlimits()
|
||||||
|
->where('transaction_currency_id', $currency->id)
|
||||||
|
->where('start_date', $start->format('Y-m-d'))
|
||||||
|
->where('end_date', $end->format('Y-m-d'))->first();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
|
@@ -55,6 +55,16 @@ interface BudgetLimitRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function destroyBudgetLimit(BudgetLimit $budgetLimit): void;
|
public function destroyBudgetLimit(BudgetLimit $budgetLimit): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param TransactionCurrency $currency
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return BudgetLimit|null
|
||||||
|
*/
|
||||||
|
public function find(Budget $budget, TransactionCurrency $currency, Carbon $start, Carbon $end): ?BudgetLimit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO this method is not multi-currency aware.
|
* TODO this method is not multi-currency aware.
|
||||||
*
|
*
|
||||||
|
@@ -28,7 +28,6 @@ use FireflyIII\Models\Budget;
|
|||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
use FireflyIII\Models\RuleAction;
|
use FireflyIII\Models\RuleAction;
|
||||||
use FireflyIII\Models\RuleTrigger;
|
use FireflyIII\Models\RuleTrigger;
|
||||||
use FireflyIII\Models\TransactionCurrency;
|
|
||||||
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
|
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -55,7 +54,6 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
* // it's 5.
|
|
||||||
*/
|
*/
|
||||||
public function cleanupBudgets(): bool
|
public function cleanupBudgets(): bool
|
||||||
{
|
{
|
||||||
@@ -65,23 +63,14 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::debug(sprintf('Could not delete budget limit: %s', $e->getMessage()));
|
Log::debug(sprintf('Could not delete budget limit: %s', $e->getMessage()));
|
||||||
}
|
}
|
||||||
Budget::where('order', 0)->update(['order' => 100]);
|
$budgets = $this->getActiveBudgets();
|
||||||
|
/**
|
||||||
// do the clean up by hand because Sqlite can be tricky with this.
|
* @var int $index
|
||||||
$budgetLimits = BudgetLimit::orderBy('created_at', 'DESC')->get(['id', 'budget_id', 'start_date', 'end_date']);
|
* @var Budget $budget
|
||||||
$count = [];
|
*/
|
||||||
/** @var BudgetLimit $budgetLimit */
|
foreach ($budgets as $index => $budget) {
|
||||||
foreach ($budgetLimits as $budgetLimit) {
|
$budget->order = $index + 1;
|
||||||
$key = $budgetLimit->budget_id . '-' . $budgetLimit->start_date->format('Y-m-d') . $budgetLimit->end_date->format('Y-m-d');
|
$budget->save();
|
||||||
if (isset($count[$key])) {
|
|
||||||
// delete it!
|
|
||||||
try {
|
|
||||||
BudgetLimit::find($budgetLimit->id)->delete();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::debug(sprintf('Could not delete budget limit: %s', $e->getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$count[$key] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
36
public/v1/js/ff/budgets/index.js
vendored
36
public/v1/js/ff/budgets/index.js
vendored
@@ -39,6 +39,8 @@ $(function () {
|
|||||||
$('.create_ab_alt').on('click', createAltAvailableBudget);
|
$('.create_ab_alt').on('click', createAltAvailableBudget);
|
||||||
|
|
||||||
$('.budget_amount').on('change', updateBudgetedAmount);
|
$('.budget_amount').on('change', updateBudgetedAmount);
|
||||||
|
$('.create_bl').on('click', createBudgetLimit);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When the input changes, update the percentages for the budgeted bar:
|
When the input changes, update the percentages for the budgeted bar:
|
||||||
@@ -49,8 +51,7 @@ $(function () {
|
|||||||
var selected = $(e.currentTarget);
|
var selected = $(e.currentTarget);
|
||||||
if (selected.find(":selected").val() !== "x") {
|
if (selected.find(":selected").val() !== "x") {
|
||||||
var newUri = budgetIndexUri.replace("START", selected.find(":selected").data('start')).replace('END', selected.find(":selected").data('end'));
|
var newUri = budgetIndexUri.replace("START", selected.find(":selected").data('start')).replace('END', selected.find(":selected").data('end'));
|
||||||
console.log(newUri);
|
window.location.assign(newUri);
|
||||||
window.location.assign(newUri + "?page=" + page);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -88,9 +89,9 @@ function updateBudgetedAmount(e) {
|
|||||||
var budgetId = parseInt(input.data('id'));
|
var budgetId = parseInt(input.data('id'));
|
||||||
var budgetLimitId = parseInt(input.data('limit'));
|
var budgetLimitId = parseInt(input.data('limit'));
|
||||||
var currencyId = parseInt(input.data('currency'));
|
var currencyId = parseInt(input.data('currency'));
|
||||||
console.log(budgetLimitId);
|
input.prop('disabled', true);
|
||||||
if (0 === budgetLimitId) {
|
if (0 === budgetLimitId) {
|
||||||
$.post(createBudgetLimitUri, {
|
$.post(storeBudgetLimitUri, {
|
||||||
_token: token,
|
_token: token,
|
||||||
budget_id: budgetId,
|
budget_id: budgetId,
|
||||||
transaction_currency_id: currencyId,
|
transaction_currency_id: currencyId,
|
||||||
@@ -99,12 +100,21 @@ function updateBudgetedAmount(e) {
|
|||||||
end: periodEnd
|
end: periodEnd
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
|
|
||||||
alert('done!');
|
input.prop('disabled', false);
|
||||||
|
|
||||||
|
// update amount left.
|
||||||
|
$('.left_span[data-limit="0"][data-id="' + budgetId + '"]').html(data.left_formatted);
|
||||||
|
if (data.left_per_day > 0) {
|
||||||
|
$('.left_span[data-limit="0"][data-id="' + budgetId + '"]').html(data.left_formatted + '(' + data.left_per_day_formatted + ')');
|
||||||
|
}
|
||||||
|
console.log(data);
|
||||||
|
//$('.left_span[data-limit="0"][data-id="' + budgetId + '"]').text('XXXXX');
|
||||||
|
|
||||||
}).fail(function () {
|
}).fail(function () {
|
||||||
alert('I failed :(');
|
alert('I failed :(');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$.post(updateBudgetLimitUri.replace('REPLACEME', budgetLimitId), {
|
$.post(updateBudgetLimitUri.replace('REPLACEME', budgetLimitId.toString()), {
|
||||||
_token: token,
|
_token: token,
|
||||||
amount: input.val(),
|
amount: input.val(),
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
@@ -142,14 +152,21 @@ function sortStop(event, ui) {
|
|||||||
});
|
});
|
||||||
var arr = {
|
var arr = {
|
||||||
budgetIds: submit,
|
budgetIds: submit,
|
||||||
page: page,
|
|
||||||
_token: token
|
_token: token
|
||||||
};
|
};
|
||||||
$.post('budgets/reorder', arr);
|
$.post('budgets/reorder', arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAltAvailableBudget(e) {
|
function createBudgetLimit(e) {
|
||||||
var button = $(e.currentTarget);
|
var button = $(e.currentTarget);
|
||||||
|
var budgetId = button.data('id');
|
||||||
|
$('#defaultModal').empty().load(createBudgetLimitUri.replace('REPLACEME', budgetId.toString()), function () {
|
||||||
|
$('#defaultModal').modal('show');
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAltAvailableBudget(e) {
|
||||||
$('#defaultModal').empty().load(createAltAvailableBudgetUri, function () {
|
$('#defaultModal').empty().load(createAltAvailableBudgetUri, function () {
|
||||||
$('#defaultModal').modal('show');
|
$('#defaultModal').modal('show');
|
||||||
});
|
});
|
||||||
@@ -180,18 +197,15 @@ function drawBudgetedBars() {
|
|||||||
var bar = $(v);
|
var bar = $(v);
|
||||||
var budgeted = parseFloat(bar.data('budgeted'));
|
var budgeted = parseFloat(bar.data('budgeted'));
|
||||||
var available = parseFloat(bar.data('available'));
|
var available = parseFloat(bar.data('available'));
|
||||||
console.log('Budgeted bar for bar ' + bar.data('id'));
|
|
||||||
var budgetedTooMuch = budgeted > available;
|
var budgetedTooMuch = budgeted > available;
|
||||||
var pct;
|
var pct;
|
||||||
if (budgetedTooMuch) {
|
if (budgetedTooMuch) {
|
||||||
console.log('over budget');
|
|
||||||
// budgeted too much.
|
// budgeted too much.
|
||||||
pct = (available / budgeted) * 100;
|
pct = (available / budgeted) * 100;
|
||||||
bar.find('.progress-bar-warning').css('width', pct + '%');
|
bar.find('.progress-bar-warning').css('width', pct + '%');
|
||||||
bar.find('.progress-bar-danger').css('width', (100 - pct) + '%');
|
bar.find('.progress-bar-danger').css('width', (100 - pct) + '%');
|
||||||
bar.find('.progress-bar-info').css('width', 0);
|
bar.find('.progress-bar-info').css('width', 0);
|
||||||
} else {
|
} else {
|
||||||
console.log('under budget');
|
|
||||||
pct = (budgeted / available) * 100;
|
pct = (budgeted / available) * 100;
|
||||||
bar.find('.progress-bar-warning').css('width', 0);
|
bar.find('.progress-bar-warning').css('width', 0);
|
||||||
bar.find('.progress-bar-danger').css('width', 0);
|
bar.find('.progress-bar-danger').css('width', 0);
|
||||||
|
@@ -700,6 +700,8 @@ return [
|
|||||||
'update_amount' => 'Update amount',
|
'update_amount' => 'Update amount',
|
||||||
'update_budget' => 'Update budget',
|
'update_budget' => 'Update budget',
|
||||||
'update_budget_amount_range' => 'Update (expected) available amount between :start and :end',
|
'update_budget_amount_range' => 'Update (expected) available amount between :start and :end',
|
||||||
|
'set_budget_limit_title' => 'Set budgeted amount for budget :budget between :start and :end',
|
||||||
|
'set_budget_limit' => 'Set budgeted amount',
|
||||||
'budget_period_navigator' => 'Period navigator',
|
'budget_period_navigator' => 'Period navigator',
|
||||||
'info_on_available_amount' => 'What do I have available?',
|
'info_on_available_amount' => 'What do I have available?',
|
||||||
'available_amount_indication' => 'Use these amounts to get an indication of what your total budget could be.',
|
'available_amount_indication' => 'Use these amounts to get an indication of what your total budget could be.',
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>
|
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>
|
||||||
<input type="hidden" name="end" value="{{ end.format('Y-m-d') }}"/>
|
<input type="hidden" name="end" value="{{ end.format('Y-m-d') }}"/>
|
||||||
<input type="hidden" name="page" value="{{ page }}"/>
|
<input type="hidden" name="page" value="{{ page }}"/>
|
||||||
<input type="hidden" name="currency_id" value="{{ currency.id }}"/>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<select class="form-control" name="currency_id">
|
<select class="form-control" name="currency_id">
|
||||||
|
36
resources/views/v1/budgets/budget-limits/create.twig
Normal file
36
resources/views/v1/budgets/budget-limits/create.twig
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal"><span>×</span><span class="sr-only">{{ 'close'|_ }}</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">
|
||||||
|
{{ trans('firefly.set_budget_limit_title',
|
||||||
|
{start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat), budget: budget.name}) }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form style="display: inline;" id="income" action="{{ route('budget-limits.store') }}" method="POST">
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
|
||||||
|
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>
|
||||||
|
<input type="hidden" name="end" value="{{ end.format('Y-m-d') }}"/>
|
||||||
|
<input type="hidden" name="budget_id" value="{{ budget.id }}"/>
|
||||||
|
<div class="form-group">
|
||||||
|
<select class="form-control" name="transaction_currency_id">
|
||||||
|
{% for currency in currencies %}
|
||||||
|
<option label="{{ currency.name }}" value="{{ currency.id }}">{{ currency.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input step="any" class="form-control" id="amount" value="" autocomplete="off" name="amount" type="number"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
|
||||||
|
<button type="submit" class="btn btn-primary">{{ 'set_budget_limit'|_ }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@@ -270,7 +270,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if budget.budgeted|length < currencies.count %}
|
{% if budget.budgeted|length < currencies.count %}
|
||||||
<a href="#" class="btn btn-success btn-xs create_ab_alt">
|
<a href="#" class="btn btn-success btn-xs create_bl" data-id="{{ budget.id }}">
|
||||||
<i class="fa fa-plus-circle"></i>
|
<i class="fa fa-plus-circle"></i>
|
||||||
{{ 'bl_create_btn'|_ }}</a>
|
{{ 'bl_create_btn'|_ }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -279,26 +279,60 @@
|
|||||||
{% for spentInfo in budget.spent %}
|
{% for spentInfo in budget.spent %}
|
||||||
{{ formatAmountBySymbol(spentInfo.spent, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
|
{{ formatAmountBySymbol(spentInfo.spent, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
|
||||||
({{ formatAmountBySymbol(spentInfo.spent / activeDaysPassed, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
({{ formatAmountBySymbol(spentInfo.spent / activeDaysPassed, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
||||||
|
<br/>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td class="left" data-id="{{ budget.id }}">
|
<td class="left" data-id="{{ budget.id }}">
|
||||||
|
{% for spentInfo in budget.spent %}
|
||||||
|
{% set countLimit = 0 %}
|
||||||
|
{% for budgetLimit in budget.budgeted %}
|
||||||
|
{% if spentInfo.currency_id == budgetLimit.currency_id %}
|
||||||
|
{% set countLimit = countLimit + 1 %}
|
||||||
|
<span class="left_span" data-currency="{{ spentInfo.currency_id }}" data-limit="{{ budgetLimit.id }}"
|
||||||
|
data-value="{{ spentInfo.spent + budgetLimit.amount }}" class="amount_left">
|
||||||
|
{{ formatAmountBySymbol(spentInfo.spent + budgetLimit.amount, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
|
||||||
|
{% if spentInfo.spent + budgetLimit.amount > 0 %}
|
||||||
|
({{ formatAmountBySymbol((spentInfo.spent + budgetLimit.amount) / activeDaysLeft, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
||||||
|
{% else %}
|
||||||
|
({{ formatAmountBySymbol(0, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<br/>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if countLimit == 0 %}
|
||||||
|
<span class="left_span" data-id="{{ budget.id }}" data-currency="{{ spentInfo.currency_id }}" data-limit="0"
|
||||||
|
class="amount_left" data-value="{{ spentInfo.spent }}">
|
||||||
|
{{ formatAmountBySymbol(spentInfo.spent, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
|
||||||
|
</span>
|
||||||
|
<br/>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<!-- only makes sense to list what's left for budgeted amounts.-->
|
<!-- only makes sense to list what's left for budgeted amounts.-->
|
||||||
|
|
||||||
|
<!--
|
||||||
{% if budget.budgeted|length > 0 %}
|
{% if budget.budgeted|length > 0 %}
|
||||||
{% for budgetLimit in budget.budgeted %}
|
{% for budgetLimit in budget.budgeted %}
|
||||||
{% for spentInfo in budget.spent %}
|
{% for spentInfo in budget.spent %}
|
||||||
{% if spentInfo.currency_id == budgetLimit.currency_id %}
|
{% if spentInfo.currency_id == budgetLimit.currency_id %}
|
||||||
|
<span data-currency="{{ spentInfo.currency_id }}" data-limit="{{ budgetLimit.id }}" class="amount_left">
|
||||||
{{ formatAmountBySymbol(spentInfo.spent + budgetLimit.amount, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
|
{{ formatAmountBySymbol(spentInfo.spent + budgetLimit.amount, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
|
||||||
{% if spentInfo.spent + budgetLimit.amount > 0 %}
|
{% if spentInfo.spent + budgetLimit.amount > 0 %}
|
||||||
({{ formatAmountBySymbol((spentInfo.spent + budgetLimit.amount) / activeDaysLeft, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
({{ formatAmountBySymbol((spentInfo.spent + budgetLimit.amount) / activeDaysLeft, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
||||||
{% else %}
|
{% else %}
|
||||||
({{ formatAmountBySymbol(0, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
({{ formatAmountBySymbol(0, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<br/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
-->
|
||||||
|
|
||||||
{#{{ "-1"|formatAmount }}#}
|
{#{{ "-1"|formatAmount }}#}
|
||||||
{#{{ (repAmount + budgetInformation[budget.id]['spent'])|formatAmount }}#}
|
{#{{ (repAmount + budgetInformation[budget.id]['spent'])|formatAmount }}#}
|
||||||
@@ -381,7 +415,8 @@
|
|||||||
var createAltAvailableBudgetUri = "{{ route('available-budgets.create-alternative', [start.format('Y-m-d'), end.format('Y-m-d')]) }}";
|
var createAltAvailableBudgetUri = "{{ route('available-budgets.create-alternative', [start.format('Y-m-d'), end.format('Y-m-d')]) }}";
|
||||||
var editAvailableBudgetUri = "{{ route('available-budgets.edit', ['REPLACEME']) }}";
|
var editAvailableBudgetUri = "{{ route('available-budgets.edit', ['REPLACEME']) }}";
|
||||||
|
|
||||||
var createBudgetLimitUri = "{{ route('budget-limits.store') }}";
|
var createBudgetLimitUri = "{{ route('budget-limits.create', ['REPLACEME',start.format('Y-m-d'), end.format('Y-m-d')]) }}";
|
||||||
|
var storeBudgetLimitUri = "{{ route('budget-limits.store') }}";
|
||||||
var updateBudgetLimitUri = "{{ route('budget-limits.update', ['REPLACEME']) }}";
|
var updateBudgetLimitUri = "{{ route('budget-limits.update', ['REPLACEME']) }}";
|
||||||
|
|
||||||
{#var budgetAmountUri = "{{ route('budgets.amount','REPLACE') }}";#}
|
{#var budgetAmountUri = "{{ route('budgets.amount','REPLACE') }}";#}
|
||||||
|
@@ -258,8 +258,11 @@ Route::group(
|
|||||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'budget-limits', 'as' => 'budget-limits.'],
|
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'budget-limits', 'as' => 'budget-limits.'],
|
||||||
static function () {
|
static function () {
|
||||||
|
|
||||||
Route::get('delete/{budgetLimit}', ['uses' => 'Budget\BudgetLimitController@delete', 'as' => 'delete']);
|
Route::get('create/{budget}/{start_date}/{end_date}', ['uses' => 'Budget\BudgetLimitController@create', 'as' => 'create']);
|
||||||
Route::post('store', ['uses' => 'Budget\BudgetLimitController@store', 'as' => 'store']);
|
Route::post('store', ['uses' => 'Budget\BudgetLimitController@store', 'as' => 'store']);
|
||||||
|
|
||||||
|
Route::get('delete/{budgetLimit}', ['uses' => 'Budget\BudgetLimitController@delete', 'as' => 'delete']);
|
||||||
|
|
||||||
Route::post('update/{budgetLimit}', ['uses' => 'Budget\BudgetLimitController@update', 'as' => 'update']);
|
Route::post('update/{budgetLimit}', ['uses' => 'Budget\BudgetLimitController@update', 'as' => 'update']);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user