mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-16 09:22:33 +00:00
Merge branch 'release/3.4'
This commit is contained in:
18
.env.backup
Executable file
18
.env.backup
Executable file
@@ -0,0 +1,18 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_DRIVER=smtp
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=
|
18
.env.local
Executable file
18
.env.local
Executable file
@@ -0,0 +1,18 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_DRIVER=smtp
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ tests/_output/*
|
||||
clover.xml
|
||||
node_modules/
|
||||
addNewLines.php
|
||||
.phpstorm.meta.php
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Firefly III (v3.3.9)
|
||||
Firefly III (v3.4)
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/JC5/firefly-iii)
|
||||
|
@@ -65,6 +65,22 @@ class ConnectJournalToPiggyBank
|
||||
}
|
||||
|
||||
Log::debug('Found rep! ' . $repetition->id);
|
||||
|
||||
/*
|
||||
* Add amount when
|
||||
*/
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if ($transaction->account_id == $piggyBank->account_id) {
|
||||
if ($transaction->amount < 0) {
|
||||
$amount = $amount * -1;
|
||||
Log::debug('Transaction is away from piggy, so amount becomes ' . $amount);
|
||||
} else {
|
||||
Log::debug('Transaction is to from piggy, so amount stays ' . $amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$repetition->currentamount += $amount;
|
||||
$repetition->save();
|
||||
|
||||
|
@@ -11,6 +11,7 @@ use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,7 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('mainTitleIcon', 'fa-credit-card');
|
||||
View::share('title', 'Accounts');
|
||||
}
|
||||
@@ -39,6 +41,12 @@ class AccountController extends Controller
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = 'Create a new ' . e($what) . ' account';
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('accounts.create.fromStore') !== true) {
|
||||
Session::put('accounts.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('accounts.create.fromStore');
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
|
||||
|
||||
}
|
||||
@@ -52,6 +60,9 @@ class AccountController extends Controller
|
||||
{
|
||||
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
|
||||
|
||||
// put previous url in session
|
||||
Session::put('accounts.delete.url', URL::previous());
|
||||
|
||||
return view('accounts.delete', compact('account', 'subTitle'));
|
||||
}
|
||||
|
||||
@@ -71,7 +82,7 @@ class AccountController extends Controller
|
||||
|
||||
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.');
|
||||
|
||||
return Redirect::route('accounts.index', $typeName);
|
||||
return Redirect::to(Session::get('accounts.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,6 +99,12 @@ class AccountController extends Controller
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$openingBalance = $repository->openingBalanceTransaction($account);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('accounts.edit.fromUpdate') !== true) {
|
||||
Session::put('accounts.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('accounts.edit.fromUpdate');
|
||||
|
||||
// pre fill some useful values.
|
||||
|
||||
// the opening balance is tricky:
|
||||
@@ -184,10 +201,15 @@ class AccountController extends Controller
|
||||
Session::flash('success', 'New account "' . $account->name . '" stored!');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
return Redirect::route('accounts.create', $request->input('what'))->withInput();
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('accounts.create.fromStore', true);
|
||||
|
||||
return Redirect::route('accounts.create')->withInput();
|
||||
}
|
||||
|
||||
return Redirect::route('accounts.index', $request->input('what'));
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('accounts.create.url'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -200,7 +222,7 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function update(Account $account, AccountFormRequest $request, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
|
||||
$accountData = [
|
||||
'name' => $request->input('name'),
|
||||
'active' => $request->input('active'),
|
||||
@@ -219,10 +241,14 @@ class AccountController extends Controller
|
||||
Session::flash('success', 'Account "' . $account->name . '" updated.');
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
return Redirect::route('accounts.edit', $account->id);
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('accounts.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('accounts.edit', $account->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
return Redirect::route('accounts.index', $what);
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('accounts.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Message;
|
||||
use Mail;
|
||||
use Session;
|
||||
use Twig;
|
||||
|
||||
/**
|
||||
* Class AuthController
|
||||
@@ -47,6 +48,16 @@ class AuthController extends Controller
|
||||
$this->middleware('guest', ['except' => 'getLogout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application login form.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function getLogin()
|
||||
{
|
||||
return Twig::render('auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a registration request for the application.
|
||||
*
|
||||
|
@@ -29,6 +29,7 @@ class BillController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Bills');
|
||||
View::share('mainTitleIcon', 'fa-calendar-o');
|
||||
}
|
||||
@@ -83,6 +84,12 @@ class BillController extends Controller
|
||||
{
|
||||
$periods = Config::get('firefly.periods_to_text');
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('bills.create.fromStore') !== true) {
|
||||
Session::put('bills.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('bills.create.fromStore');
|
||||
|
||||
return view('bills.create')->with('periods', $periods)->with('subTitle', 'Create new');
|
||||
}
|
||||
|
||||
@@ -93,6 +100,9 @@ class BillController extends Controller
|
||||
*/
|
||||
public function delete(Bill $bill)
|
||||
{
|
||||
// put previous url in session
|
||||
Session::put('bills.delete.url', URL::previous());
|
||||
|
||||
return view('bills.delete')->with('bill', $bill)->with('subTitle', 'Delete "' . e($bill->name) . '"');
|
||||
}
|
||||
|
||||
@@ -107,7 +117,7 @@ class BillController extends Controller
|
||||
|
||||
Session::flash('success', 'The bill was deleted.');
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
return Redirect::to(Session::get('bills.delete.url'));
|
||||
|
||||
}
|
||||
|
||||
@@ -120,6 +130,12 @@ class BillController extends Controller
|
||||
{
|
||||
$periods = Config::get('firefly.periods_to_text');
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('bills.edit.fromUpdate') !== true) {
|
||||
Session::put('bills.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('bills.edit.fromUpdate');
|
||||
|
||||
return view('bills.edit')->with('periods', $periods)->with('bill', $bill)->with('subTitle', 'Edit "' . e($bill->name) . '"');
|
||||
}
|
||||
|
||||
@@ -190,10 +206,14 @@ class BillController extends Controller
|
||||
Session::flash('success', 'Bill "' . e($bill->name) . '" stored.');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('bills.create.fromStore', true);
|
||||
|
||||
return Redirect::route('bills.create')->withInput();
|
||||
}
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('bills.create.url'));
|
||||
|
||||
}
|
||||
|
||||
@@ -207,13 +227,17 @@ class BillController extends Controller
|
||||
$billData = $request->getBillData();
|
||||
$bill = $repository->update($bill, $billData);
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
return Redirect::route('bills.edit', $bill->id);
|
||||
}
|
||||
|
||||
Session::flash('success', 'Bill "' . e($bill->name) . '" updated.');
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('bills.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('bills.edit', $bill->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('bills.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
@@ -29,8 +29,10 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Budgets');
|
||||
View::share('mainTitleIcon', 'fa-tasks');
|
||||
View::share('hideBudgets', true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,12 +187,12 @@ class BudgetController extends Controller
|
||||
return view('error')->with('message', 'Invalid selection.');
|
||||
}
|
||||
|
||||
$hideBudget = true; // used in transaction list.
|
||||
$journals = $repository->getJournals($budget, $repetition);
|
||||
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $repository->getBudgetLimits($budget);
|
||||
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
|
||||
$journals = $repository->getJournals($budget, $repetition);
|
||||
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $repository->getBudgetLimits($budget);
|
||||
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
|
||||
$journals->setPath('/budgets/show/' . $budget->id);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget'));
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -26,6 +26,7 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Categories');
|
||||
View::share('mainTitleIcon', 'fa-bar-chart');
|
||||
}
|
||||
@@ -51,7 +52,7 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function delete(Category $category)
|
||||
{
|
||||
$subTitle = 'Delete category' . e($category->name) . '"';
|
||||
$subTitle = 'Delete category "' . e($category->name) . '"';
|
||||
|
||||
// put previous url in session
|
||||
Session::put('categories.delete.url', URL::previous());
|
||||
|
@@ -3,6 +3,7 @@
|
||||
use Illuminate\Foundation\Bus\DispatchesCommands;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class Controller
|
||||
@@ -14,4 +15,14 @@ abstract class Controller extends BaseController
|
||||
|
||||
use DispatchesCommands, ValidatesRequests;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('hideBudgets', false);
|
||||
View::share('hideCategories', false);
|
||||
View::share('hideBills', false);
|
||||
View::share('hideTags', false);
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ class CurrencyController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
parent::__construct();
|
||||
View::share('title', 'Currencies');
|
||||
View::share('mainTitleIcon', 'fa-usd');
|
||||
}
|
||||
|
@@ -144,8 +144,8 @@ class GoogleChartController extends Controller
|
||||
public function allBudgetsHomeChart(GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
$chart->addColumn('Left', 'number');
|
||||
//$chart->addColumn('Spent', 'number');
|
||||
|
||||
$budgets = $repository->getBudgets();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
@@ -171,7 +171,8 @@ class GoogleChartController extends Controller
|
||||
|
||||
foreach ($allEntries as $entry) {
|
||||
if ($entry[2] > 0) {
|
||||
$chart->addRow($entry[0], $entry[1], $entry[2]);
|
||||
$left = $entry[1] - $entry[2];
|
||||
$chart->addRow($entry[0], $left);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +359,7 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function budgetsAndSpending(Budget $budget, $year = 0, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
public function budgetsAndSpending(GChart $chart, BudgetRepositoryInterface $repository, Budget $budget, $year = 0)
|
||||
{
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
|
@@ -1,12 +1,8 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Cache;
|
||||
use ErrorException;
|
||||
use FireflyIII\Helpers\Help\HelpInterface;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Log;
|
||||
use Response;
|
||||
use Route;
|
||||
|
||||
/**
|
||||
* Class HelpController
|
||||
|
@@ -86,7 +86,7 @@ class HomeController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal','piggyBankAccounts'));
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts'));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -12,6 +11,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use Response;
|
||||
@@ -180,6 +180,23 @@ class JsonController extends Controller
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all beneficiaries.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function tags(TagRepositoryInterface $tagRepository)
|
||||
{
|
||||
$list = $tagRepository->get();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->tag;
|
||||
}
|
||||
|
||||
return Response::json($return);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
|
@@ -32,6 +32,7 @@ class PiggyBankController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ class PreferencesController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
parent::__construct();
|
||||
View::share('title', 'Preferences');
|
||||
View::share('mainTitleIcon', 'fa-gear');
|
||||
}
|
||||
|
@@ -49,7 +49,8 @@ class ProfileController extends Controller
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function postDeleteAccount(DeleteAccountFormRequest $request) {
|
||||
public function postDeleteAccount(DeleteAccountFormRequest $request)
|
||||
{
|
||||
// old, new1, new2
|
||||
if (!Hash::check($request->get('password'), Auth::user()->password)) {
|
||||
Session::flash('error', 'Invalid password!');
|
||||
@@ -60,11 +61,11 @@ class ProfileController extends Controller
|
||||
// DELETE!
|
||||
Auth::user()->delete();
|
||||
Session::flush();
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
|
@@ -1,164 +0,0 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use URL;
|
||||
|
||||
/**
|
||||
* Class RelatedController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class RelatedController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function alreadyRelated(TransactionJournal $journal)
|
||||
{
|
||||
$ids = [];
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($journal->transactiongroups()->get() as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$ids[] = $loopJournal->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
$unique = array_unique($ids);
|
||||
$journals = new Collection;
|
||||
if (count($unique) > 0) {
|
||||
$journals = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
|
||||
}
|
||||
$parent = $journal;
|
||||
|
||||
return view('related.alreadyRelated', compact('parent', 'journals'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @param TransactionJournal $parentJournal
|
||||
* @param TransactionJournal $childJournal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getRemoveRelation(TransactionJournal $parentJournal, TransactionJournal $childJournal)
|
||||
{
|
||||
$groups = $parentJournal->transactiongroups()->get();
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id == $childJournal->id) {
|
||||
// remove from group:
|
||||
$group->transactionjournals()->detach($childJournal);
|
||||
}
|
||||
}
|
||||
if ($group->transactionjournals()->count() == 1) {
|
||||
$group->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return Redirect::to(URL::previous());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $parentJournal
|
||||
* @param TransactionJournal $childJournal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function relate(TransactionJournal $parentJournal, TransactionJournal $childJournal)
|
||||
{
|
||||
$group = new TransactionGroup;
|
||||
$group->relation = 'balance';
|
||||
$group->user_id = Auth::user()->id;
|
||||
$group->save();
|
||||
$group->transactionjournals()->save($parentJournal);
|
||||
$group->transactionjournals()->save($childJournal);
|
||||
|
||||
return Response::json(true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function related(TransactionJournal $journal)
|
||||
{
|
||||
$groups = $journal->transactiongroups()->get();
|
||||
$members = new Collection;
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$members->push($loopJournal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('related.relate', compact('journal', 'members'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @param TransactionJournal $parentJournal
|
||||
* @param TransactionJournal $childJournal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function removeRelation(TransactionJournal $parentJournal, TransactionJournal $childJournal)
|
||||
{
|
||||
$groups = $parentJournal->transactiongroups()->get();
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id == $childJournal->id) {
|
||||
// remove from group:
|
||||
$group->transactionjournals()->detach($childJournal);
|
||||
}
|
||||
}
|
||||
if ($group->transactionjournals()->count() == 1) {
|
||||
$group->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return Response::json(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function search(TransactionJournal $journal, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$search = e(trim(Input::get('searchValue')));
|
||||
$parent = $journal;
|
||||
|
||||
$journals = $repository->searchRelated($search, $journal);
|
||||
|
||||
return view('related.searchResult', compact('journals', 'search', 'parent'));
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -47,50 +47,51 @@ class ReportController extends Controller
|
||||
*/
|
||||
public function budget($year = '2014', $month = '1')
|
||||
{
|
||||
try {
|
||||
new Carbon($year . '-' . $month . '-01');
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid date');
|
||||
}
|
||||
$date = new Carbon($year . '-' . $month . '-01');
|
||||
$start = clone $date;
|
||||
$date = new Carbon($year . '-' . $month . '-01');
|
||||
$subTitle = 'Budget report for ' . $date->format('F Y');
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$start = clone $date;
|
||||
|
||||
|
||||
$start->startOfMonth();
|
||||
$end = clone $date;
|
||||
$end->endOfMonth();
|
||||
$start->subDay();
|
||||
|
||||
// should show shared reports?
|
||||
/** @var Preference $pref */
|
||||
$pref = Preferences::get('showSharedReports', false);
|
||||
$showSharedReports = $pref->data;
|
||||
$accountAmounts = []; // array with sums of spent amounts on each account.
|
||||
$accounts = $this->query->getAllAccounts($start, $end, $showSharedReports); // all accounts and some data.
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
|
||||
$dayEarly = clone $date;
|
||||
$subTitle = 'Budget report for ' . $date->format('F Y');
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$dayEarly = $dayEarly->subDay();
|
||||
$accounts = $this->query->getAllAccounts($start, $end, $showSharedReports);
|
||||
$start->addDay();
|
||||
$budgets = $this->query->getBudgetSummary($account, $start, $end);// get budget summary for this account:
|
||||
$balancedAmount = $this->query->balancedTransactionsSum($account, $start, $end);
|
||||
$accountAmounts[$account->id] = $balancedAmount;
|
||||
// balance out the transactions (see transaction groups & tags) ^^
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $end) {
|
||||
$budgets = $this->query->getBudgetSummary($account, $start, $end);
|
||||
$balancedAmount = $this->query->balancedTransactionsSum($account, $start, $end);
|
||||
$array = [];
|
||||
$hide = true;
|
||||
foreach ($budgets as $budget) {
|
||||
$id = intval($budget->id);
|
||||
$data = $budget->toArray();
|
||||
$array[$id] = $data;
|
||||
if (floatval($data['queryAmount']) != 0) {
|
||||
$hide = false;
|
||||
}
|
||||
// array with budget information for each account:
|
||||
$array = [];
|
||||
// should always hide account
|
||||
$hide = true;
|
||||
// loop all budgets
|
||||
foreach ($budgets as $budget) {
|
||||
$id = intval($budget->id);
|
||||
$data = $budget->toArray();
|
||||
$array[$id] = $data;
|
||||
|
||||
// no longer hide account if any budget has money in it.
|
||||
if (floatval($data['queryAmount']) != 0) {
|
||||
$hide = false;
|
||||
}
|
||||
$account->hide = $hide;
|
||||
$account->budgetInformation = $array;
|
||||
$account->balancedAmount = $balancedAmount;
|
||||
|
||||
$accountAmounts[$account->id] += $data['queryAmount'];
|
||||
}
|
||||
);
|
||||
$account->hide = $hide;
|
||||
$account->budgetInformation = $array;
|
||||
$account->balancedAmount = $balancedAmount;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Start getBudgetsForMonth DONE
|
||||
@@ -101,7 +102,7 @@ class ReportController extends Controller
|
||||
* End getBudgetsForMonth DONE
|
||||
*/
|
||||
|
||||
return view('reports.budget', compact('subTitle', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
|
||||
return view('reports.budget', compact('subTitle', 'accountAmounts', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets'));
|
||||
|
||||
}
|
||||
|
||||
|
314
app/Http/Controllers/TagController.php
Normal file
314
app/Http/Controllers/TagController.php
Normal file
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests\TagFormRequest;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class TagController
|
||||
*
|
||||
* Remember: a balancingAct takes at most one expense and one transfer.
|
||||
* an advancePayment takes at most one expense, infinite deposits and NO transfers.
|
||||
*
|
||||
* TODO transaction can only have one advancePayment OR balancingAct.
|
||||
* TODO Other attempts to put in such a tag are blocked.
|
||||
* TODO also show an error when editing a tag and it becomes either
|
||||
* TODO of these two types. Or rather, block editing of the tag.
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Tags');
|
||||
View::share('mainTitleIcon', 'fa-tags');
|
||||
View::share('hideTags', true);
|
||||
$tagOptions = [
|
||||
'nothing' => 'Just a regular tag.',
|
||||
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
||||
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||
];
|
||||
View::share('tagOptions', $tagOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$subTitle = 'New tag';
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
$preFilled = [
|
||||
'tagMode' => 'nothing'
|
||||
];
|
||||
if (!Input::old('tagMode')) {
|
||||
Session::flash('preFilled', $preFilled);
|
||||
}
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('tags.create.fromStore') !== true) {
|
||||
Session::put('tags.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('tags.create.fromStore');
|
||||
|
||||
return view('tags.create', compact('subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function delete(Tag $tag)
|
||||
{
|
||||
$subTitle = 'Delete "' . e($tag->tag) . '"';
|
||||
|
||||
// put previous url in session
|
||||
Session::put('tags.delete.url', URL::previous());
|
||||
|
||||
return view('tags.delete', compact('tag', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Tag $tag, TagRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$tagName = $tag->tag;
|
||||
$repository->destroy($tag);
|
||||
|
||||
Session::flash('success', 'Tag "' . e($tagName) . '" was deleted.');
|
||||
|
||||
return Redirect::to(route('tags.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Tag $tag)
|
||||
{
|
||||
$subTitle = 'Edit tag "' . e($tag->tag) . '"';
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
/*
|
||||
* Default tag options (again)
|
||||
*/
|
||||
$tagOptions = [
|
||||
'nothing' => 'Just a regular tag.',
|
||||
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
||||
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||
];
|
||||
|
||||
/*
|
||||
* Can this tag become another type?
|
||||
*/
|
||||
$allowToAdvancePayment = true;
|
||||
$allowToBalancingAct = true;
|
||||
|
||||
/*
|
||||
* If this tag is a balancing act, and it contains transfers, it cannot be
|
||||
* changes to an advancePayment.
|
||||
*/
|
||||
|
||||
if ($tag->tagMode == 'balancingAct') {
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
$allowToAdvancePayment = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this tag contains more than one expenses, it cannot become an advance payment.
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if($count > 1) {
|
||||
$allowToAdvancePayment = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If has more than two transactions already, cannot become a balancing act:
|
||||
*/
|
||||
if ($tag->transactionjournals->count() > 2) {
|
||||
$allowToBalancingAct = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any transaction is a deposit, cannot become a balancing act.
|
||||
*/
|
||||
$count = 0;
|
||||
foreach ($tag->transactionjournals as $journal) {
|
||||
if ($journal->transactionType->type == 'Deposit') {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if($count > 0) {
|
||||
$allowToBalancingAct = false;
|
||||
}
|
||||
|
||||
|
||||
// edit tagoptions:
|
||||
if ($allowToAdvancePayment === false) {
|
||||
unset($tagOptions['advancePayment']);
|
||||
}
|
||||
if ($allowToBalancingAct === false) {
|
||||
unset($tagOptions['balancingAct']);
|
||||
}
|
||||
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('tags.edit.fromUpdate') !== true) {
|
||||
Session::put('tags.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('tags.edit.fromUpdate');
|
||||
|
||||
return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'tagOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
*/
|
||||
public function hideTagHelp($state)
|
||||
{
|
||||
|
||||
$state = $state == 'true' ? true : false;
|
||||
Preferences::set('hideTagHelp', $state);
|
||||
|
||||
return Response::json(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
/** @var Preference $helpHiddenPref */
|
||||
$helpHiddenPref = Preferences::get('hideTagHelp', false);
|
||||
$title = 'Tags';
|
||||
$mainTitleIcon = 'fa-tags';
|
||||
$helpHidden = $helpHiddenPref->data;
|
||||
$tags = Auth::user()->tags()->get();
|
||||
|
||||
return view('tags.index', compact('title', 'mainTitleIcon', 'helpHidden', 'tags'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Tag $tag)
|
||||
{
|
||||
$subTitle = $tag->tag;
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
return view('tags.show', compact('tag', 'subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TagFormRequest $request
|
||||
*/
|
||||
public function store(TagFormRequest $request, TagRepositoryInterface $repository)
|
||||
{
|
||||
if (Input::get('setTag') == 'true') {
|
||||
$latitude = strlen($request->get('latitude')) > 0 ? $request->get('latitude') : null;
|
||||
$longitude = strlen($request->get('longitude')) > 0 ? $request->get('longitude') : null;
|
||||
$zoomLevel = strlen($request->get('zoomLevel')) > 0 ? $request->get('zoomLevel') : null;
|
||||
} else {
|
||||
$latitude = null;
|
||||
$longitude = null;
|
||||
$zoomLevel = null;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'tag' => $request->get('tag'),
|
||||
'date' => strlen($request->get('date')) > 0 ? new Carbon($request->get('date')) : null,
|
||||
'description' => strlen($request->get('description')) > 0 ? $request->get('description') : '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'zoomLevel' => $zoomLevel,
|
||||
'tagMode' => $request->get('tagMode'),
|
||||
];
|
||||
$repository->store($data);
|
||||
|
||||
Session::flash('success', 'The tag has been created!');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('tags.create.fromStore', true);
|
||||
|
||||
return Redirect::route('tags.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('tags.create.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*/
|
||||
public function update(Tag $tag, TagFormRequest $request, TagRepositoryInterface $repository)
|
||||
{
|
||||
if (Input::get('setTag') == 'true') {
|
||||
$latitude = strlen($request->get('latitude')) > 0 ? $request->get('latitude') : null;
|
||||
$longitude = strlen($request->get('longitude')) > 0 ? $request->get('longitude') : null;
|
||||
$zoomLevel = strlen($request->get('zoomLevel')) > 0 ? $request->get('zoomLevel') : null;
|
||||
} else {
|
||||
$latitude = null;
|
||||
$longitude = null;
|
||||
$zoomLevel = null;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'tag' => $request->get('tag'),
|
||||
'date' => strlen($request->get('date')) > 0 ? new Carbon($request->get('date')) : null,
|
||||
'description' => strlen($request->get('description')) > 0 ? $request->get('description') : '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'zoomLevel' => $zoomLevel,
|
||||
'tagMode' => $request->get('tagMode'),
|
||||
];
|
||||
|
||||
$repository->update($tag, $data);
|
||||
|
||||
Session::flash('success', 'Tag "' . e($data['tag']) . '" updated.');
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('tags.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('tags.edit', $tag->id)->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('tags.edit.url'));
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ class TransactionController extends Controller
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Transactions');
|
||||
View::share('mainTitleIcon', 'fa-repeat');
|
||||
}
|
||||
@@ -134,6 +135,12 @@ class TransactionController extends Controller
|
||||
'budget_id' => 0,
|
||||
'piggy_bank_id' => 0
|
||||
];
|
||||
// get tags:
|
||||
$tags = [];
|
||||
foreach ($journal->tags as $tag) {
|
||||
$tags[] = $tag->tag;
|
||||
}
|
||||
$preFilled['tags'] = join(',', $tags);
|
||||
|
||||
$category = $journal->categories()->first();
|
||||
if (!is_null($category)) {
|
||||
@@ -150,12 +157,14 @@ class TransactionController extends Controller
|
||||
}
|
||||
|
||||
$preFilled['amount'] = $journal->amount;
|
||||
$preFilled['account_id'] = $repository->getAssetAccount($journal);
|
||||
$preFilled['account_id'] = $journal->assetAccount->id;
|
||||
$preFilled['expense_account'] = $transactions[0]->account->name;
|
||||
$preFilled['revenue_account'] = $transactions[1]->account->name;
|
||||
$preFilled['account_from_id'] = $transactions[1]->account->id;
|
||||
$preFilled['account_to_id'] = $transactions[0]->account->id;
|
||||
|
||||
Session::flash('preFilled', $preFilled);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('transactions.edit.fromUpdate') !== true) {
|
||||
Session::put('transactions.edit.url', URL::previous());
|
||||
@@ -271,6 +280,7 @@ class TransactionController extends Controller
|
||||
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
|
||||
$journalData = $request->getJournalData();
|
||||
$journal = $repository->store($journalData);
|
||||
|
||||
|
@@ -42,6 +42,7 @@ class JournalFormRequest extends Request
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'budget_id' => intval($this->get('budget_id')),
|
||||
'category' => $this->get('category'),
|
||||
'tags' => explode(',', $this->get('tags')),
|
||||
];
|
||||
}
|
||||
|
||||
|
53
app/Http/Requests/TagFormRequest.php
Normal file
53
app/Http/Requests/TagFormRequest.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 27/04/15
|
||||
* Time: 12:50
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Tag;
|
||||
use Input;
|
||||
|
||||
/**
|
||||
* Class TagFormRequest
|
||||
*
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class TagFormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// Only allow logged in users
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$idRule = '';
|
||||
$tagRule = 'required|min:1|uniqueObjectForUser:tags,tag,TRUE';
|
||||
if (Tag::find(Input::get('id'))) {
|
||||
$idRule = 'belongsToUser:tags';
|
||||
$tagRule = 'required|min:1|uniqueObjectForUser:tags,tag,TRUE,' . Input::get('id');
|
||||
}
|
||||
|
||||
return [
|
||||
'tag' => $tagRule,
|
||||
'id' => $idRule,
|
||||
'description' => 'min:1',
|
||||
'date' => 'date',
|
||||
'latitude' => 'numeric|min:-90|max:90',
|
||||
'longitude' => 'numeric|min:-90|max:90',
|
||||
'tagMode' => 'required|in:nothing,balancingAct,advancePayment'
|
||||
];
|
||||
}
|
||||
}
|
@@ -9,8 +9,9 @@ use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Reminder;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
|
||||
use FireflyIII\Models\Tag;
|
||||
/*
|
||||
* Back home.
|
||||
*/
|
||||
@@ -22,6 +23,14 @@ Breadcrumbs::register(
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'index',
|
||||
function (Generator $breadcrumbs) {
|
||||
|
||||
$breadcrumbs->push('Home', route('index'));
|
||||
}
|
||||
);
|
||||
|
||||
// accounts
|
||||
Breadcrumbs::register(
|
||||
'accounts.index', function (Generator $breadcrumbs, $what) {
|
||||
@@ -95,6 +104,13 @@ Breadcrumbs::register(
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.noBudget', function (Generator $breadcrumbs, $subTitle) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
$breadcrumbs->push($subTitle, route('budgets.noBudget'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
@@ -142,6 +158,34 @@ Breadcrumbs::register(
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.noCategory', function (Generator $breadcrumbs, $subTitle) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push($subTitle, route('categories.noCategory'));
|
||||
}
|
||||
);
|
||||
|
||||
// currencies.
|
||||
Breadcrumbs::register(
|
||||
'currency.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Currencies', route('currency.index'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'currency.edit', function (Generator $breadcrumbs, TransactionCurrency $currency) {
|
||||
$breadcrumbs->parent('currency.index');
|
||||
$breadcrumbs->push('Edit '.$currency->name, route('currency.edit', $currency->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'currency.delete', function (Generator $breadcrumbs, TransactionCurrency $currency) {
|
||||
$breadcrumbs->parent('currency.index');
|
||||
$breadcrumbs->push('Delete '.$currency->name, route('currency.delete', $currency->id));
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// piggy banks
|
||||
Breadcrumbs::register(
|
||||
@@ -350,3 +394,24 @@ Breadcrumbs::register(
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// tags
|
||||
Breadcrumbs::register(
|
||||
'tags.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Tags', route('tags.index'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'tags.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('tags.index');
|
||||
$breadcrumbs->push('Create tag', route('tags.create'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'tags.show', function (Generator $breadcrumbs, Tag $tag) {
|
||||
$breadcrumbs->parent('tags.index');
|
||||
$breadcrumbs->push(e($tag->tag), route('tags.show', $tag));
|
||||
}
|
||||
);
|
@@ -6,8 +6,10 @@ use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Reminder;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
|
||||
// models
|
||||
@@ -15,102 +17,113 @@ Route::bind(
|
||||
'account',
|
||||
function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
$account = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->where('account_types.editable', 1)
|
||||
->where('accounts.id', $value)
|
||||
->where('user_id', Auth::user()->id)
|
||||
->first(['accounts.*']);
|
||||
if ($account) {
|
||||
return $account;
|
||||
$object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->where('account_types.editable', 1)
|
||||
->where('accounts.id', $value)
|
||||
->where('user_id', Auth::user()->id)
|
||||
->first(['accounts.*']);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
App::abort(404);
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tjSecond', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return TransactionJournal::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tj', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return TransactionJournal::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = TransactionJournal::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'currency', function ($value, $route) {
|
||||
return TransactionCurrency::find($value);
|
||||
if (Auth::check()) {
|
||||
$object = TransactionCurrency::find($value);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'bill', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Bill::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = Bill::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'budget', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Budget::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = Budget::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'reminder', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
$object = Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'limitrepetition', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return LimitRepetition::where('limit_repetitions.id', $value)
|
||||
->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id')
|
||||
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
|
||||
->where('budgets.user_id', Auth::user()->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
$object = LimitRepetition::where('limit_repetitions.id', $value)
|
||||
->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id')
|
||||
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
|
||||
->where('budgets.user_id', Auth::user()->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'piggyBank', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return PiggyBank::
|
||||
where('piggy_banks.id', $value)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
|
||||
->where('accounts.user_id', Auth::user()->id)
|
||||
->first(['piggy_banks.*']);
|
||||
$object = PiggyBank::where('piggy_banks.id', $value)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
|
||||
->where('accounts.user_id', Auth::user()->id)
|
||||
->first(['piggy_banks.*']);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -118,9 +131,25 @@ Route::bind(
|
||||
'category', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Category::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
$object = $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tag', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Tag::where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
if ($object) {
|
||||
$object = $object;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -245,6 +274,7 @@ Route::group(
|
||||
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']);
|
||||
Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
|
||||
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']);
|
||||
Route::get('/json/tags', ['uses' => 'JsonController@tags', 'as' => 'json.tags']);
|
||||
Route::get('/json/box/in', ['uses' => 'JsonController@boxIn', 'as' => 'json.box.in']);
|
||||
Route::get('/json/box/out', ['uses' => 'JsonController@boxOut', 'as' => 'json.box.out']);
|
||||
Route::get('/json/box/bills-unpaid', ['uses' => 'JsonController@boxBillsUnpaid', 'as' => 'json.box.paid']);
|
||||
@@ -286,16 +316,6 @@ Route::group(
|
||||
Route::post('/profile/delete-account', ['uses' => 'ProfileController@postDeleteAccount', 'as' => 'delete-account-post']);
|
||||
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword', 'as' => 'change-password-post']);
|
||||
|
||||
/**
|
||||
* Related transactions controller
|
||||
*/
|
||||
Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']);
|
||||
Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']);
|
||||
Route::post('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']);
|
||||
Route::get('/related/remove/{tj}/{tjSecond}', ['uses' => 'RelatedController@getRemoveRelation', 'as' => 'related.getRemoveRelation']);
|
||||
Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']);
|
||||
Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']);
|
||||
|
||||
/**
|
||||
* Reminder Controller
|
||||
*/
|
||||
@@ -327,6 +347,22 @@ Route::group(
|
||||
*/
|
||||
Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']);
|
||||
|
||||
/**
|
||||
* Tag Controller
|
||||
*/
|
||||
Route::get('/tags', ['uses' => 'TagController@index', 'as' => 'tags.index']);
|
||||
Route::get('/tags/create', ['uses' => 'TagController@create', 'as' => 'tags.create']);
|
||||
Route::get('/tags/show/{tag}', ['uses' => 'TagController@show', 'as' => 'tags.show']);
|
||||
Route::get('/tags/edit/{tag}', ['uses' => 'TagController@edit', 'as' => 'tags.edit']);
|
||||
Route::get('/tags/delete/{tag}', ['uses' => 'TagController@delete', 'as' => 'tags.delete']);
|
||||
|
||||
Route::post('/tags/store', ['uses' => 'TagController@store', 'as' => 'tags.store']);
|
||||
Route::post('/tags/update/{tag}', ['uses' => 'TagController@update', 'as' => 'tags.update']);
|
||||
Route::post('/tags/destroy/{tag}', ['uses' => 'TagController@destroy', 'as' => 'tags.destroy']);
|
||||
|
||||
Route::post('/tags/hideTagHelp/{state}', ['uses' => 'TagController@hideTagHelp', 'as' => 'tags.hideTagHelp']);
|
||||
|
||||
|
||||
/**
|
||||
* Transaction Controller
|
||||
*/
|
||||
|
@@ -14,7 +14,7 @@ class PiggyBank extends Model
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable
|
||||
= ['name', 'account_id', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me'];
|
||||
= ['name', 'account_id','order', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me'];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
|
128
app/Models/Tag.php
Normal file
128
app/Models/Tag.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use App;
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
/**
|
||||
* Class Tag
|
||||
*
|
||||
* @package FireflyIII\Models
|
||||
*/
|
||||
class Tag extends Model
|
||||
{
|
||||
use ValidatingTrait;
|
||||
|
||||
protected $fillable = ['user_id', 'tag', 'date', 'description', 'longitude', 'latitude', 'zoomLevel', 'tagMode'];
|
||||
protected $rules
|
||||
= [
|
||||
'tag' => 'required|min:1|uniqueObjectForUser:tags,tag,TRUE',
|
||||
'description' => 'min:1',
|
||||
'date' => 'date',
|
||||
'latitude' => 'numeric|min:-90|max:90',
|
||||
'longitude' => 'numeric|min:-90|max:90',
|
||||
'tagMode' => 'required|in:nothing,balancingAct,advancePayment'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*
|
||||
* @return Tag|null
|
||||
*/
|
||||
public static function firstOrCreateEncrypted(array $fields)
|
||||
{
|
||||
// everything but the tag:
|
||||
if (isset($fields['tagMode'])) {
|
||||
unset($fields['tagMode']);
|
||||
}
|
||||
$query = Tag::orderBy('id');
|
||||
foreach ($fields as $name => $value) {
|
||||
if ($name != 'tag') {
|
||||
$query->where($name, $value);
|
||||
}
|
||||
}
|
||||
$set = $query->get(['tags.*']);
|
||||
/** @var Tag $tag */
|
||||
foreach ($set as $tag) {
|
||||
if ($tag->tag == $fields['tag']) {
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
// create it!
|
||||
$fields['tagMode'] = 'nothing';
|
||||
$fields['description'] = isset($fields['description']) && !is_null($fields['description']) ? $fields['description'] : '';
|
||||
$tag = Tag::create($fields);
|
||||
if (is_null($tag->id)) {
|
||||
// could not create account:
|
||||
App::abort(500, 'Could not create new tag with data: ' . json_encode($fields) . ' because ' . json_encode($tag->getErrors()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $tag;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getDates()
|
||||
{
|
||||
return ['created_at', 'updated_at', 'date'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescriptionAttribute($value)
|
||||
{
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTagAttribute($value)
|
||||
{
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setDescriptionAttribute($value)
|
||||
{
|
||||
$this->attributes['description'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setTagAttribute($value)
|
||||
{
|
||||
$this->attributes['tag'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function transactionjournals()
|
||||
{
|
||||
return $this->belongsToMany('FireflyIII\Models\TransactionJournal');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('FireflyIII\User');
|
||||
}
|
||||
}
|
@@ -68,6 +68,34 @@ class TransactionJournal extends Model
|
||||
}
|
||||
}
|
||||
|
||||
public function getAssetAccountAttribute()
|
||||
{
|
||||
$positive = true; // the asset account is in the transaction with the positive amount.
|
||||
if ($this->transactionType->type === 'Withdrawal') {
|
||||
$positive = false;
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($this->transactions()->get() as $transaction) {
|
||||
if (floatval($transaction->amount) > 0 && $positive === true) {
|
||||
return $transaction->account;
|
||||
}
|
||||
if (floatval($transaction->amount) < 0 && $positive === false) {
|
||||
return $transaction->account;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->transactions()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('FireflyIII\Models\Transaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -201,6 +229,14 @@ class TransactionJournal extends Model
|
||||
$this->attributes['encrypted'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
return $this->belongsToMany('FireflyIII\Models\Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
@@ -225,14 +261,6 @@ class TransactionJournal extends Model
|
||||
return $this->belongsToMany('FireflyIII\Models\TransactionGroup');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('FireflyIII\Models\Transaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
|
@@ -35,6 +35,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
'Illuminate\Contracts\Auth\Registrar',
|
||||
'FireflyIII\Services\Registrar'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,7 +23,227 @@ class ConfigServiceProvider extends ServiceProvider
|
||||
{
|
||||
config(
|
||||
[
|
||||
//
|
||||
'twigbridge' => [
|
||||
|
||||
'twig' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Extension
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| File extension for Twig view files.
|
||||
|
|
||||
*/
|
||||
'extension' => 'twig',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Accepts all Twig environment configuration options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| http://twig.sensiolabs.org/doc/api.html#environment-options
|
||||
|
|
||||
*/
|
||||
'environment' => [
|
||||
|
||||
// When set to true, the generated templates have a __toString() method
|
||||
// that you can use to display the generated nodes.
|
||||
// default: false
|
||||
'debug' => config('app.debug', false),
|
||||
|
||||
// The charset used by the templates.
|
||||
// default: utf-8
|
||||
'charset' => 'utf-8',
|
||||
|
||||
// The base template class to use for generated templates.
|
||||
// default: TwigBridge\Twig\Template
|
||||
'base_template_class' => 'TwigBridge\Twig\Template',
|
||||
|
||||
// An absolute path where to store the compiled templates, or false to disable caching. If null
|
||||
// then the cache file path is used.
|
||||
// default: cache file storage path
|
||||
'cache' => null,
|
||||
|
||||
// When developing with Twig, it's useful to recompile the template
|
||||
// whenever the source code changes. If you don't provide a value
|
||||
// for the auto_reload option, it will be determined automatically based on the debug value.
|
||||
'auto_reload' => true,
|
||||
|
||||
// If set to false, Twig will silently ignore invalid variables
|
||||
// (variables and or attributes/methods that do not exist) and
|
||||
// replace them with a null value. When set to true, Twig throws an exception instead.
|
||||
// default: false
|
||||
'strict_variables' => false,
|
||||
|
||||
// If set to true, auto-escaping will be enabled by default for all templates.
|
||||
// default: true
|
||||
'autoescape' => true,
|
||||
|
||||
// A flag that indicates which optimizations to apply
|
||||
// (default to -1 -- all optimizations are enabled; set it to 0 to disable)
|
||||
'optimizations' => -1,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These will always be passed in and can be accessed as Twig variables.
|
||||
| NOTE: these will be overwritten if you pass data into the view with the same key.
|
||||
|
|
||||
*/
|
||||
'globals' => [],
|
||||
],
|
||||
|
||||
'extensions' => [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Extensions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enabled extensions.
|
||||
|
|
||||
| `Twig_Extension_Debug` is enabled automatically if twig.debug is TRUE.
|
||||
|
|
||||
*/
|
||||
'enabled' => [
|
||||
'TwigBridge\Extension\Loader\Facades',
|
||||
'TwigBridge\Extension\Loader\Filters',
|
||||
'TwigBridge\Extension\Loader\Functions',
|
||||
|
||||
'TwigBridge\Extension\Laravel\Auth',
|
||||
'TwigBridge\Extension\Laravel\Config',
|
||||
'TwigBridge\Extension\Laravel\Dump',
|
||||
'TwigBridge\Extension\Laravel\Input',
|
||||
'TwigBridge\Extension\Laravel\Session',
|
||||
'TwigBridge\Extension\Laravel\String',
|
||||
'TwigBridge\Extension\Laravel\Translator',
|
||||
'TwigBridge\Extension\Laravel\Url',
|
||||
|
||||
// 'TwigBridge\Extension\Laravel\Form',
|
||||
// 'TwigBridge\Extension\Laravel\Html',
|
||||
// 'TwigBridge\Extension\Laravel\Legacy\Facades',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Facades
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available facades. Access like `{{ Config.get('foo.bar') }}`.
|
||||
|
|
||||
| Each facade can take an optional array of options. To mark the whole facade
|
||||
| as safe you can set the option `'is_safe' => true`. Setting the facade as
|
||||
| safe means that any HTML returned will not be escaped.
|
||||
|
|
||||
| It is advisable to not set the whole facade as safe and instead mark the
|
||||
| each appropriate method as safe for security reasons. You can do that with
|
||||
| the following syntax:
|
||||
|
|
||||
| <code>
|
||||
| 'Form' => [
|
||||
| 'is_safe' => [
|
||||
| 'open'
|
||||
| ]
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
| The values of the `is_safe` array must match the called method on the facade
|
||||
| in order to be marked as safe.
|
||||
|
|
||||
*/
|
||||
'facades' => [
|
||||
'Breadcrumbs' => [
|
||||
'is_safe' => [
|
||||
'renderIfExists'
|
||||
]
|
||||
],
|
||||
'Session',
|
||||
'Route',
|
||||
'Auth',
|
||||
'URL',
|
||||
'Config',
|
||||
'ExpandedForm' => [
|
||||
'is_safe' => [
|
||||
'date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location',
|
||||
'multiRadio'
|
||||
]
|
||||
],
|
||||
'Form' => [
|
||||
'is_safe' => [
|
||||
'input', 'select', 'checkbox', 'model', 'open','radio','textarea'
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Functions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available functions. Access like `{{ secure_url(...) }}`.
|
||||
|
|
||||
| Each function can take an optional array of options. These options are
|
||||
| passed directly to `Twig_SimpleFunction`.
|
||||
|
|
||||
| So for example, to mark a function as safe you can do the following:
|
||||
|
|
||||
| <code>
|
||||
| 'link_to' => [
|
||||
| 'is_safe' => ['html']
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
| The options array also takes a `callback` that allows you to name the
|
||||
| function differently in your Twig templates than what it's actually called.
|
||||
|
|
||||
| <code>
|
||||
| 'link' => [
|
||||
| 'callback' => 'link_to'
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
*/
|
||||
'functions' => [
|
||||
'elixir',
|
||||
'head',
|
||||
'last',
|
||||
'old'
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available filters. Access like `{{ variable|filter }}`.
|
||||
|
|
||||
| Each filter can take an optional array of options. These options are
|
||||
| passed directly to `Twig_SimpleFilter`.
|
||||
|
|
||||
| So for example, to mark a filter as safe you can do the following:
|
||||
|
|
||||
| <code>
|
||||
| 'studly_case' => [
|
||||
| 'is_safe' => ['html']
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
| The options array also takes a `callback` that allows you to name the
|
||||
| filter differently in your Twig templates than what is actually called.
|
||||
|
|
||||
| <code>
|
||||
| 'snake' => [
|
||||
| 'callback' => 'snake_case'
|
||||
| ]
|
||||
| </code>
|
||||
|
|
||||
*/
|
||||
'filters' => [],
|
||||
],
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@@ -2,13 +2,21 @@
|
||||
|
||||
namespace FireflyIII\Providers;
|
||||
|
||||
use App;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Support\Amount;
|
||||
use FireflyIII\Support\ExpandedForm;
|
||||
use FireflyIII\Support\Navigation;
|
||||
use FireflyIII\Support\Preferences;
|
||||
use FireflyIII\Support\Steam;
|
||||
use FireflyIII\Support\Twig\Budget;
|
||||
use FireflyIII\Support\Twig\General;
|
||||
use FireflyIII\Support\Twig\Journal;
|
||||
use FireflyIII\Support\Twig\PiggyBank;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Twig;
|
||||
use TwigBridge\Extension\Loader\Functions;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
@@ -25,10 +33,22 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
return new FireflyValidator($translator, $data, $rules, $messages);
|
||||
}
|
||||
);
|
||||
/*
|
||||
* Default Twig configuration:
|
||||
*/
|
||||
|
||||
$config = App::make('config');
|
||||
Twig::addExtension(new Functions($config));
|
||||
Twig::addExtension(new PiggyBank);
|
||||
Twig::addExtension(new General);
|
||||
Twig::addExtension(new Journal);
|
||||
Twig::addExtension(new Budget);
|
||||
}
|
||||
|
||||
public function register()
|
||||
{
|
||||
|
||||
|
||||
$this->app->bind(
|
||||
'preferences', function () {
|
||||
return new Preferences;
|
||||
@@ -63,6 +83,7 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Currency\CurrencyRepositoryInterface', 'FireflyIII\Repositories\Currency\CurrencyRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Tag\TagRepositoryInterface', 'FireflyIII\Repositories\Tag\TagRepository');
|
||||
$this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search');
|
||||
|
||||
|
||||
@@ -71,6 +92,7 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper');
|
||||
$this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery');
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,10 +4,12 @@ namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use App;
|
||||
use Auth;
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
@@ -32,36 +34,6 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
return Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the account_id, which is the asset account that paid for the transaction.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAssetAccount(TransactionJournal $journal)
|
||||
{
|
||||
$positive = true; // the asset account is in the transaction with the positive amount.
|
||||
switch ($journal->transactionType->type) {
|
||||
case 'Withdrawal':
|
||||
$positive = false;
|
||||
break;
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if (floatval($transaction->amount) > 0 && $positive === true) {
|
||||
return $transaction->account_id;
|
||||
}
|
||||
if (floatval($transaction->amount) < 0 && $positive === false) {
|
||||
return $transaction->account_id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $journal->transactions()->first()->account_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionType $dbType
|
||||
*
|
||||
@@ -83,55 +55,26 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Collection
|
||||
* * Remember: a balancingAct takes at most one expense and one transfer.
|
||||
* an advancePayment takes at most one expense, infinite deposits and NO transfers.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function searchRelated($query, TransactionJournal $journal)
|
||||
public function saveTags(TransactionJournal $journal, array $array)
|
||||
{
|
||||
$start = clone $journal->date;
|
||||
$end = clone $journal->date;
|
||||
$start->startOfMonth();
|
||||
$end->endOfMonth();
|
||||
/** @var \FireflyIII\Repositories\Tag\TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||
|
||||
// get already related transactions:
|
||||
$exclude = [$journal->id];
|
||||
foreach ($journal->transactiongroups()->get() as $group) {
|
||||
foreach ($group->transactionjournals()->get() as $current) {
|
||||
$exclude[] = $current->id;
|
||||
foreach ($array as $name) {
|
||||
if (strlen(trim($name)) > 0) {
|
||||
$tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]);
|
||||
$tagRepository->connect($journal, $tag);
|
||||
}
|
||||
}
|
||||
$exclude = array_unique($exclude);
|
||||
|
||||
/** @var Collection $collection */
|
||||
$collection = Auth::user()->transactionjournals()
|
||||
->withRelevantData()
|
||||
->before($end)->after($start)->where('encrypted', 0)
|
||||
->whereNotIn('id', $exclude)
|
||||
->where('description', 'LIKE', '%' . $query . '%')
|
||||
->get();
|
||||
|
||||
// manually search encrypted entries:
|
||||
/** @var Collection $encryptedCollection */
|
||||
$encryptedCollection = Auth::user()->transactionjournals()
|
||||
->withRelevantData()
|
||||
->before($end)->after($start)
|
||||
->where('encrypted', 1)
|
||||
->whereNotIn('id', $exclude)
|
||||
->get();
|
||||
$encrypted = $encryptedCollection->filter(
|
||||
function (TransactionJournal $journal) use ($query) {
|
||||
$strPos = strpos(strtolower($journal->description), strtolower($query));
|
||||
if ($strPos !== false) {
|
||||
return $journal;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
return $collection->merge($encrypted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,6 +134,11 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
$journal->completed = 1;
|
||||
$journal->save();
|
||||
|
||||
// store tags
|
||||
if (isset($data['tags']) && is_array($data['tags'])) {
|
||||
$this->saveTags($journal, $data['tags']);
|
||||
}
|
||||
|
||||
return $journal;
|
||||
|
||||
|
||||
@@ -246,9 +194,54 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
$journal->save();
|
||||
|
||||
// update tags:
|
||||
if (isset($data['tags']) && is_array($data['tags'])) {
|
||||
$this->updateTags($journal, $data['tags']);
|
||||
}
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateTags(TransactionJournal $journal, array $array)
|
||||
{
|
||||
// create tag repository
|
||||
/** @var \FireflyIII\Repositories\Tag\TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||
|
||||
|
||||
// find or create all tags:
|
||||
$tags = [];
|
||||
$ids = [];
|
||||
foreach ($array as $name) {
|
||||
if (strlen(trim($name)) > 0) {
|
||||
$tag = Tag::firstOrCreateEncrypted(['tag' => $name, 'user_id' => $journal->user_id]);
|
||||
$tags[] = $tag;
|
||||
$ids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
|
||||
// delete all tags connected to journal not in this array:
|
||||
if (count($ids) > 0) {
|
||||
DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->whereNotIn('tag_id', $ids)->delete();
|
||||
}
|
||||
// if count is zero, delete them all:
|
||||
if(count($ids) == 0) {
|
||||
DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal->id)->delete();
|
||||
}
|
||||
|
||||
// connect each tag to journal (if not yet connected):
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
$tagRepository->connect($journal, $tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionType $type
|
||||
* @param array $data
|
||||
|
@@ -21,16 +21,6 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function first();
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the account_id, which is the asset account that paid for the transaction.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getAssetAccount(TransactionJournal $journal);
|
||||
|
||||
/**
|
||||
* @param TransactionType $dbType
|
||||
*
|
||||
@@ -38,21 +28,28 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function getJournalsOfType(TransactionType $dbType);
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function searchRelated($query, TransactionJournal $journal);
|
||||
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return TransactionType
|
||||
*/
|
||||
public function getTransactionType($type);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
|
||||
/**
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveTags(TransactionJournal $journal, array $array);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -67,4 +64,12 @@ interface JournalRepositoryInterface
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(TransactionJournal $journal, array $data);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param array $array
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateTags(TransactionJournal $journal, array $array);
|
||||
}
|
||||
|
@@ -140,12 +140,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
|
||||
|
||||
$set->sortBy(
|
||||
function (PiggyBank $piggyBank) {
|
||||
return $piggyBank->name;
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
|
180
app/Repositories/Tag/TagRepository.php
Normal file
180
app/Repositories/Tag/TagRepository.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Tag;
|
||||
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class TagRepository
|
||||
*
|
||||
* @package FireflyIII\Repositories\Tag
|
||||
*/
|
||||
class TagRepository implements TagRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function connect(TransactionJournal $journal, Tag $tag)
|
||||
{
|
||||
|
||||
/*
|
||||
* Already connected:
|
||||
*/
|
||||
if ($journal->tags()->find($tag->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($tag->tagMode == 'nothing') {
|
||||
// save it, no problem:
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* get some withdrawal types:
|
||||
*/
|
||||
/** @var TransactionType $withdrawal */
|
||||
$withdrawal = TransactionType::whereType('Withdrawal')->first();
|
||||
/** @var TransactionType $deposit */
|
||||
$deposit = TransactionType::whereType('Deposit')->first();
|
||||
/** @var TransactionType $transfer */
|
||||
$transfer = TransactionType::whereType('Transfer')->first();
|
||||
|
||||
$withdrawals = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->count();
|
||||
$transfers = $tag->transactionjournals()->where('transaction_type_id', $transfer->id)->count();
|
||||
|
||||
if ($tag->tagMode == 'balancingAct') {
|
||||
|
||||
// only if this is the only withdrawal.
|
||||
if ($journal->transaction_type_id == $withdrawal->id && $withdrawals < 1) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
// and only if this is the only transfer
|
||||
if ($journal->transaction_type_id == $transfer->id && $transfers < 1) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ignore expense
|
||||
return false;
|
||||
}
|
||||
if ($tag->tagMode == 'advancePayment') {
|
||||
|
||||
|
||||
// only if this is the only withdrawal
|
||||
if ($journal->transaction_type_id == $withdrawal->id && $withdrawals < 1) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// only if this is a deposit.
|
||||
if ($journal->transaction_type_id == $deposit->id) {
|
||||
|
||||
// if this is a deposit, account must match the current only journal
|
||||
// (if already present):
|
||||
$currentWithdrawal = $tag->transactionjournals()->where('transaction_type_id', $withdrawal->id)->first();
|
||||
|
||||
if ($currentWithdrawal && $currentWithdrawal->assetAccount->id == $journal->assetAccount->id) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (is_null($currentWithdrawal)) {
|
||||
$journal->tags()->save($tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function destroy(Tag $tag)
|
||||
{
|
||||
$tag->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
/** @var Collection $tags */
|
||||
$tags = Auth::user()->tags()->get();
|
||||
$tags->sortBy(
|
||||
function (Tag $tag) {
|
||||
return $tag->tag;
|
||||
}
|
||||
);
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
$tag = new Tag;
|
||||
$tag->tag = $data['tag'];
|
||||
$tag->date = $data['date'];
|
||||
$tag->description = $data['description'];
|
||||
$tag->latitude = $data['latitude'];
|
||||
$tag->longitude = $data['longitude'];
|
||||
$tag->zoomLevel = $data['zoomLevel'];
|
||||
$tag->tagMode = $data['tagMode'];
|
||||
$tag->user()->associate(Auth::user());
|
||||
$tag->save();
|
||||
|
||||
return $tag;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function update(Tag $tag, array $data)
|
||||
{
|
||||
$tag->tag = $data['tag'];
|
||||
$tag->date = $data['date'];
|
||||
$tag->description = $data['description'];
|
||||
$tag->latitude = $data['latitude'];
|
||||
$tag->longitude = $data['longitude'];
|
||||
$tag->zoomLevel = $data['zoomLevel'];
|
||||
$tag->tagMode = $data['tagMode'];
|
||||
$tag->save();
|
||||
|
||||
return $tag;
|
||||
}
|
||||
}
|
50
app/Repositories/Tag/TagRepositoryInterface.php
Normal file
50
app/Repositories/Tag/TagRepositoryInterface.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Tag;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Interface TagRepositoryInterface
|
||||
*
|
||||
* @package FireflyIII\Repositories\Tag
|
||||
*/
|
||||
interface TagRepositoryInterface {
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get();
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
* @param array $data
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
public function update(Tag $tag, array $data);
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function destroy(Tag $tag);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function connect(TransactionJournal $journal, Tag $tag);
|
||||
}
|
@@ -160,12 +160,15 @@ class Amount
|
||||
|
||||
$currencyPreference = Prefs::get('currencyPreference', 'EUR');
|
||||
$currency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
if ($currency) {
|
||||
|
||||
\Cache::forever('FFCURRENCYCODE', $currency->code);
|
||||
Cache::forever('FFCURRENCYCODE', $currency->code);
|
||||
define('FFCURRENCYCODE', $currency->code);
|
||||
|
||||
define('FFCURRENCYCODE', $currency->code);
|
||||
return $currency->code;
|
||||
}
|
||||
|
||||
return $currency->code;
|
||||
return 'EUR';
|
||||
}
|
||||
|
||||
public function getDefaultCurrency()
|
||||
|
@@ -62,7 +62,10 @@ class ExpandedForm
|
||||
'account_id' => 'Asset account',
|
||||
'budget_id' => 'Budget',
|
||||
'openingBalance' => 'Opening balance',
|
||||
'tagMode' => 'Tag mode',
|
||||
'tagPosition' => 'Tag location',
|
||||
'virtualBalance' => 'Virtual balance',
|
||||
'longitude_latitude' => 'Location',
|
||||
'targetamount' => 'Target amount',
|
||||
'accountRole' => 'Account role',
|
||||
'openingBalanceDate' => 'Opening balance date',
|
||||
@@ -201,15 +204,17 @@ class ExpandedForm
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function month($name, $value = null, array $options = [])
|
||||
public function integer($name, $value = null, array $options = [])
|
||||
{
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$html = View::make('form.month', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$options['step'] = '1';
|
||||
$html = View::make('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,14 +224,13 @@ class ExpandedForm
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function integer($name, $value = null, array $options = [])
|
||||
public function location($name, $value = null, array $options = [])
|
||||
{
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$options['step'] = '1';
|
||||
$html = View::make('form.integer', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$html = View::make('form.location', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
|
||||
@@ -265,6 +269,44 @@ class ExpandedForm
|
||||
return $selectList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function month($name, $value = null, array $options = [])
|
||||
{
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$html = View::make('form.month', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function multiRadio($name, array $list = [], $selected = null, array $options = [])
|
||||
{
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$selected = $this->fillFieldValue($name, $selected);
|
||||
|
||||
unset($options['class']);
|
||||
$html = View::make('form.multiRadio', compact('classes', 'name', 'label', 'selected', 'options', 'list'))->render();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $name
|
||||
@@ -336,4 +378,24 @@ class ExpandedForm
|
||||
return $html;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function textarea($name, $value = null, array $options = [])
|
||||
{
|
||||
$label = $this->label($name, $options);
|
||||
$options = $this->expandOptionArray($name, $label, $options);
|
||||
$classes = $this->getHolderClasses($name);
|
||||
$value = $this->fillFieldValue($name, $value);
|
||||
$options['rows'] = 4;
|
||||
$html = View::make('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render();
|
||||
|
||||
return $html;
|
||||
|
||||
}
|
||||
}
|
||||
|
53
app/Support/Twig/Budget.php
Normal file
53
app/Support/Twig/Budget.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use Auth;
|
||||
use DB;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Class Budget
|
||||
*
|
||||
* @package FireflyIII\Support\Twig
|
||||
*/
|
||||
class Budget extends Twig_Extension
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'spentInRepetition', function (LimitRepetition $repetition) {
|
||||
$sum = DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id')
|
||||
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('transaction_journals.date', '>=', $repetition->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $repetition->enddate->format('Y-m-d'))
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->whereNull('transactions.deleted_at')
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('limit_repetitions.id', '=', $repetition->id)
|
||||
->sum('transactions.amount');
|
||||
|
||||
return floatval($sum);
|
||||
}
|
||||
);
|
||||
|
||||
return $functions;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\Budget';
|
||||
}
|
||||
}
|
146
app/Support/Twig/General.php
Normal file
146
app/Support/Twig/General.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use App;
|
||||
use Config;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Route;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Class TwigSupport
|
||||
*
|
||||
* @package FireflyIII\Support
|
||||
*/
|
||||
class General extends Twig_Extension
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
$filters = [];
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatAmount', function ($string) {
|
||||
return App::make('amount')->format($string);
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatTransaction', function (Transaction $transaction) {
|
||||
return App::make('amount')->formatTransaction($transaction);
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatAmountPlain', function ($string) {
|
||||
return App::make('amount')->format($string, false);
|
||||
}
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'formatJournal', function ($journal) {
|
||||
return App::make('amount')->formatJournal($journal);
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'balance', function (Account $account = null) {
|
||||
if (is_null($account)) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
return App::make('steam')->balance($account);
|
||||
}
|
||||
);
|
||||
|
||||
// should be a function but OK
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'getAccountRole', function ($name) {
|
||||
return Config::get('firefly.accountRoles.' . $name);
|
||||
}
|
||||
);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = [];
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'getCurrencyCode', function () {
|
||||
return App::make('amount')->getCurrencyCode();
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'getCurrencySymbol', function () {
|
||||
return App::make('amount')->getCurrencySymbol();
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'phpdate', function ($str) {
|
||||
return date($str);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'env', function ($name, $default) {
|
||||
return env($name, $default);
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'activeRoute', function ($context) {
|
||||
$args = func_get_args();
|
||||
$route = $args[1];
|
||||
$what = isset($args[2]) ? $args[2] : false;
|
||||
$strict = isset($args[3]) ? $args[3] : false;
|
||||
$activeWhat = isset($context['what']) ? $context['what'] : false;
|
||||
|
||||
// activeRoute
|
||||
if (!($what === false)) {
|
||||
if ($what == $activeWhat && Route::getCurrentRoute()->getName() == $route) {
|
||||
return 'active because-active-what';
|
||||
}
|
||||
} else {
|
||||
if (!$strict && !(strpos(Route::getCurrentRoute()->getName(), $route) === false)) {
|
||||
return 'active because-route-matches-non-strict';
|
||||
} else {
|
||||
if ($strict && Route::getCurrentRoute()->getName() == $route) {
|
||||
return 'active because-route-matches-strict';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'not-xxx-at-all';
|
||||
}, ['needs_context' => true]
|
||||
);
|
||||
|
||||
return $functions;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\General';
|
||||
}
|
||||
|
||||
}
|
99
app/Support/Twig/Journal.php
Normal file
99
app/Support/Twig/Journal.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
|
||||
use App;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFilter;
|
||||
use Twig_SimpleFunction;
|
||||
|
||||
/**
|
||||
* Class Journal
|
||||
*
|
||||
* @package FireflyIII\Support\Twig
|
||||
*/
|
||||
class Journal extends Twig_Extension
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
$filters = [];
|
||||
|
||||
$filters[] = new Twig_SimpleFilter(
|
||||
'typeIcon', function (TransactionJournal $journal) {
|
||||
$type = $journal->transactionType->type;
|
||||
if ($type == 'Withdrawal') {
|
||||
return '<span class="glyphicon glyphicon-arrow-left" title="Withdrawal"></span>';
|
||||
}
|
||||
if ($type == 'Deposit') {
|
||||
return '<span class="glyphicon glyphicon-arrow-right" title="Deposit"></span>';
|
||||
}
|
||||
if ($type == 'Transfer') {
|
||||
return '<i class="fa fa-fw fa-exchange" title="Transfer"></i>';
|
||||
}
|
||||
if ($type == 'Opening balance') {
|
||||
return '<span class="glyphicon glyphicon-ban-circle" title="Opening balance"></span>';
|
||||
}
|
||||
|
||||
|
||||
}, ['is_safe' => ['html']]
|
||||
);
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = [];
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'invalidJournal', function (TransactionJournal $journal) {
|
||||
if (!isset($journal->transactions[1]) || !isset($journal->transactions[0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'relevantTags', function (TransactionJournal $journal) {
|
||||
if ($journal->tags->count() == 0) {
|
||||
return App::make('amount')->formatJournal($journal);
|
||||
}
|
||||
foreach ($journal->tags as $tag) {
|
||||
if ($tag->tagMode == 'balancingAct') {
|
||||
// return tag formatted for a "balancing act".
|
||||
$amount = App::make('amount')->formatJournal($journal, false);
|
||||
|
||||
return '<a href="' . route('tags.show', $tag->id) . '" class="label label-success" title="' . $amount
|
||||
. '"><i class="fa fa-fw fa-refresh"></i> ' . $tag->tag . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 'TODO: ' . $journal->amount;
|
||||
}
|
||||
);
|
||||
|
||||
return $functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the extension.
|
||||
*
|
||||
* @return string The extension name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\Journals';
|
||||
}
|
||||
}
|
41
app/Support/Twig/PiggyBank.php
Normal file
41
app/Support/Twig/PiggyBank.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use Twig_Extension;
|
||||
use Twig_SimpleFunction;
|
||||
use FireflyIII\Models\PiggyBank as PB;
|
||||
|
||||
/**
|
||||
* Class PiggyBank
|
||||
*
|
||||
* @package FireflyIII\Support\Twig
|
||||
*/
|
||||
class PiggyBank extends Twig_Extension
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = [];
|
||||
|
||||
$functions[] = new Twig_SimpleFunction(
|
||||
'currentRelevantRepAmount', function (PB $piggyBank) {
|
||||
return $piggyBank->currentRelevantRep()->currentamount;
|
||||
}
|
||||
);
|
||||
return $functions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the extension.
|
||||
*
|
||||
* @return string The extension name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'FireflyIII\Support\Twig\PiggyBank';
|
||||
}
|
||||
}
|
@@ -43,6 +43,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||
return $this->hasMany('FireflyIII\Models\Account');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
return $this->hasMany('FireflyIII\Models\Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
|
@@ -13,6 +13,7 @@ use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Log;
|
||||
use Navigation;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Class FireflyValidator
|
||||
@@ -22,6 +23,18 @@ use Navigation;
|
||||
class FireflyValidator extends Validator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param TranslatorInterface $translator
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param array $messages
|
||||
* @param array $customAttributes
|
||||
*/
|
||||
public function __construct(TranslatorInterface $translator, array $data, array $rules, array $messages = [], array $customAttributes = [])
|
||||
{
|
||||
parent::__construct($translator, $data, $rules, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $attribute
|
||||
* @param $value
|
||||
@@ -181,10 +194,14 @@ class FireflyValidator extends Validator
|
||||
*/
|
||||
public function validateUniqueObjectForUser($attribute, $value, $parameters)
|
||||
{
|
||||
$table = $parameters[0];
|
||||
$field = $parameters[1];
|
||||
$encrypted = isset($parameters[2]) ? $parameters[2] : 'encrypted';
|
||||
$exclude = isset($parameters[3]) ? $parameters[3] : null;
|
||||
$table = $parameters[0];
|
||||
$field = $parameters[1];
|
||||
$encrypted = isset($parameters[2]) ? $parameters[2] : 'encrypted';
|
||||
$exclude = isset($parameters[3]) ? $parameters[3] : null;
|
||||
$alwaysEncrypted = false;
|
||||
if ($encrypted == 'TRUE') {
|
||||
$alwaysEncrypted = true;
|
||||
}
|
||||
|
||||
$query = DB::table($table)->where('user_id', Auth::user()->id);
|
||||
|
||||
@@ -195,8 +212,12 @@ class FireflyValidator extends Validator
|
||||
|
||||
$set = $query->get();
|
||||
foreach ($set as $entry) {
|
||||
$isEncrypted = intval($entry->$encrypted) == 1 ? true : false;
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->$field) : $entry->$field;
|
||||
if (!$alwaysEncrypted) {
|
||||
$isEncrypted = intval($entry->$encrypted) == 1 ? true : false;
|
||||
} else {
|
||||
$isEncrypted = true;
|
||||
}
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->$field) : $entry->$field;
|
||||
if ($checkValue == $value) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
realpath(__DIR__ . '/../')
|
||||
);
|
||||
@@ -26,6 +27,8 @@ $app = new Illuminate\Foundation\Application(
|
||||
|
|
||||
*/
|
||||
|
||||
|
||||
|
||||
$app->singleton(
|
||||
'Illuminate\Contracts\Http\Kernel',
|
||||
'FireflyIII\Http\Kernel'
|
||||
@@ -41,6 +44,9 @@ $app->singleton(
|
||||
'FireflyIII\Exceptions\Handler'
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Return The Application
|
||||
|
@@ -26,7 +26,9 @@
|
||||
"watson/validating": "~1.0",
|
||||
"doctrine/dbal": "~2.5",
|
||||
"illuminate/html": "~5.0",
|
||||
"league/commonmark": "0.7.*"
|
||||
"league/commonmark": "0.7.*",
|
||||
"rcrowe/twigbridge": "0.7.x@dev",
|
||||
"twig/extensions": "~1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "@stable",
|
||||
|
198
composer.lock
generated
198
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "0d43c4c85607c5cdc901cde2d18b75d5",
|
||||
"hash": "e3e90dd365b74f4878cf3b5b4a1c4007",
|
||||
"packages": [
|
||||
{
|
||||
"name": "classpreloader/classpreloader",
|
||||
@@ -943,16 +943,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.0.27",
|
||||
"version": "v5.0.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "4d6330118a295086ce9ff8eed2200d5b67f17688"
|
||||
"reference": "06a09429322cf53e5bd4587db1060f02a291562e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/4d6330118a295086ce9ff8eed2200d5b67f17688",
|
||||
"reference": "4d6330118a295086ce9ff8eed2200d5b67f17688",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/06a09429322cf53e5bd4587db1060f02a291562e",
|
||||
"reference": "06a09429322cf53e5bd4587db1060f02a291562e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1022,7 +1022,7 @@
|
||||
"predis/predis": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver (~2.4).",
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~2.4).",
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).",
|
||||
"guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers (~5.0).",
|
||||
"iron-io/iron_mq": "Required to use the iron queue driver (~1.5).",
|
||||
@@ -1065,7 +1065,7 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2015-04-04 01:34:57"
|
||||
"time": "2015-04-21 01:44:32"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
@@ -1527,6 +1527,70 @@
|
||||
],
|
||||
"time": "2015-03-26 18:43:54"
|
||||
},
|
||||
{
|
||||
"name": "rcrowe/twigbridge",
|
||||
"version": "0.7.x-dev",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rcrowe/TwigBridge.git",
|
||||
"reference": "ac0bfb5bcdb4fcd0cd01ab8425620ff07f6af026"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/ac0bfb5bcdb4fcd0cd01ab8425620ff07f6af026",
|
||||
"reference": "ac0bfb5bcdb4fcd0cd01ab8425620ff07f6af026",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "5.0.*",
|
||||
"illuminate/view": "5.0.*",
|
||||
"php": ">=5.4.0",
|
||||
"twig/twig": "~1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/framework": "5.0.*",
|
||||
"mockery/mockery": "0.9.*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"satooshi/php-coveralls": "~0.6",
|
||||
"squizlabs/php_codesniffer": "~1.5"
|
||||
},
|
||||
"suggest": {
|
||||
"laravelcollective/html": "For bringing back html/form in Laravel 5.x",
|
||||
"twig/extensions": "~1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"TwigBridge\\": "src",
|
||||
"TwigBridge\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Rob Crowe",
|
||||
"email": "hello@vivalacrowe.com"
|
||||
}
|
||||
],
|
||||
"description": "Adds the power of Twig to Laravel",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"twig"
|
||||
],
|
||||
"time": "2015-04-22 09:19:03"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v5.4.0",
|
||||
@@ -2291,6 +2355,115 @@
|
||||
],
|
||||
"time": "2015-03-31 08:12:29"
|
||||
},
|
||||
{
|
||||
"name": "twig/extensions",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig-extensions.git",
|
||||
"reference": "8cf4b9fe04077bd54fc73f4fde83347040c3b8cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/8cf4b9fe04077bd54fc73f4fde83347040c3b8cd",
|
||||
"reference": "8cf4b9fe04077bd54fc73f4fde83347040c3b8cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"twig/twig": "~1.12"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/translation": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/translation": "Allow the time_diff output to be translated"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_Extensions_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Common additional features for Twig that do not directly belong in core",
|
||||
"homepage": "http://twig.sensiolabs.org/doc/extensions/index.html",
|
||||
"keywords": [
|
||||
"i18n",
|
||||
"text"
|
||||
],
|
||||
"time": "2014-10-30 14:30:03"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9f70492f44398e276d1b81c1b43adfe6751c7b7f",
|
||||
"reference": "9f70492f44398e276d1b81c1b43adfe6751c7b7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com",
|
||||
"role": "Project Founder"
|
||||
},
|
||||
{
|
||||
"name": "Twig Team",
|
||||
"homepage": "http://twig.sensiolabs.org/contributors",
|
||||
"role": "Contributors"
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2015-04-19 08:30:27"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v1.1.0",
|
||||
@@ -3103,16 +3276,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.4.0",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5"
|
||||
"reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5",
|
||||
"reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
|
||||
"reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3159,7 +3332,7 @@
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2015-03-27 19:31:25"
|
||||
"time": "2015-04-27 22:15:08"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -4179,6 +4352,7 @@
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"rcrowe/twigbridge": 20,
|
||||
"barryvdh/laravel-debugbar": 0
|
||||
},
|
||||
"prefer-stable": false,
|
||||
|
@@ -136,7 +136,11 @@ return [
|
||||
'Illuminate\Validation\ValidationServiceProvider',
|
||||
'Illuminate\View\ViewServiceProvider',
|
||||
'Illuminate\Html\HtmlServiceProvider',
|
||||
'TwigBridge\ServiceProvider',
|
||||
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
'Barryvdh\Debugbar\ServiceProvider',
|
||||
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
@@ -149,6 +153,7 @@ return [
|
||||
'FireflyIII\Providers\FireflyServiceProvider',
|
||||
'FireflyIII\Providers\TestingServiceProvider',
|
||||
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -198,13 +203,14 @@ return [
|
||||
'View' => 'Illuminate\Support\Facades\View',
|
||||
'Form' => 'Illuminate\Html\FormFacade',
|
||||
'Html' => 'Illuminate\Html\HtmlFacade',
|
||||
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
|
||||
|
||||
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
|
||||
'Preferences' => 'FireflyIII\Support\Facades\Preferences',
|
||||
'Navigation' => 'FireflyIII\Support\Facades\Navigation',
|
||||
'Amount' => 'FireflyIII\Support\Facades\Amount',
|
||||
'Steam' => 'FireflyIII\Support\Facades\Steam',
|
||||
'ExpandedForm' => 'FireflyIII\Support\Facades\ExpandedForm',
|
||||
'Twig' => 'TwigBridge\Facade\Twig',
|
||||
|
||||
|
||||
],
|
||||
|
||||
|
@@ -14,7 +14,7 @@ return [
|
||||
*/
|
||||
|
||||
'paths' => [
|
||||
realpath(base_path('resources/views'))
|
||||
realpath(base_path('resources/twig'))
|
||||
],
|
||||
|
||||
/*
|
||||
|
75
database/migrations/2015_04_26_054507_changes_for_v3310.php
Normal file
75
database/migrations/2015_04_26_054507_changes_for_v3310.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class ChangesForV3310 extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('tag_transaction_journal');
|
||||
Schema::drop('tags');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
Schema::table(
|
||||
'transaction_groups', function (Blueprint $table) {
|
||||
|
||||
// drop column "relation"
|
||||
$table->dropColumn('relation');
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* New table!
|
||||
*/
|
||||
Schema::create(
|
||||
'tags', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->string('tag', 1024);
|
||||
$table->string('tagMode', 1024);
|
||||
$table->date('date')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->decimal('latitude', 18, 12)->nullable();
|
||||
$table->decimal('longitude', 18, 12)->nullable();
|
||||
$table->smallInteger('zoomLevel', false, true)->nullable();
|
||||
|
||||
// connect reminders to users
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Schema::create('tag_transaction_journal',function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('tag_id')->unsigned();
|
||||
$table->integer('transaction_journal_id')->unsigned();
|
||||
|
||||
// link to foreign tables.
|
||||
$table->foreign('tag_id', 'tag_grp_id')->references('id')->on('tags')->onDelete('cascade');
|
||||
$table->foreign('transaction_journal_id', 'tag_trj_id')->references('id')->on('transaction_journals')->onDelete('cascade');
|
||||
|
||||
// add unique.
|
||||
$table->unique(['tag_id', 'transaction_journal_id'], 'tag_t_joined');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
40
database/migrations/2015_04_28_075215_changes_for_v3310a.php
Normal file
40
database/migrations/2015_04_28_075215_changes_for_v3310a.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
/**
|
||||
* Class ChangesForV3310a
|
||||
*/
|
||||
class ChangesForV3310a extends Migration
|
||||
{
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table(
|
||||
'transaction_groups', function (Blueprint $table) {
|
||||
|
||||
// new column, relation.
|
||||
$table->string('relation', 50)->nullable();
|
||||
}
|
||||
);
|
||||
// make new column "relation"
|
||||
|
||||
}
|
||||
|
||||
}
|
32
database/migrations/2015_04_28_075317_changes_for_v3310b.php
Normal file
32
database/migrations/2015_04_28_075317_changes_for_v3310b.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* Class ChangesForV3310b
|
||||
*/
|
||||
class ChangesForV3310b extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// set all current entries to be "balance"
|
||||
DB::table('transaction_groups')->update(['relation' => 'balance']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
@@ -7,7 +7,7 @@
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
stopOnFailure="true"
|
||||
syntaxCheck="false">
|
||||
<testsuites>
|
||||
<testsuite name="Application Test Suite">
|
||||
@@ -24,6 +24,7 @@
|
||||
<logging>
|
||||
<log type="coverage-clover" target="./storage/coverage/clover.xml" charset="UTF-8" />
|
||||
</logging>
|
||||
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
|
3
pu.sh
3
pu.sh
@@ -1,8 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# backup .env file.
|
||||
cp .env .env.backup
|
||||
|
||||
# set testing environment
|
||||
cp .env.testing .env
|
||||
|
||||
|
@@ -5,4 +5,9 @@
|
||||
.ui-sortable-placeholder {
|
||||
display: inline-block;
|
||||
height: 1px;
|
||||
}
|
||||
#map-canvas {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px
|
||||
}
|
1
public/js/bootstrap-tagsinput.min.js.map
Executable file
1
public/js/bootstrap-tagsinput.min.js.map
Executable file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dist/bootstrap-tagsinput-angular.min.js","sources":["src/bootstrap-tagsinput-angular.js"],"names":["angular","module","directive","getItemProperty","scope","property","isFunction","$parent","item","undefined","restrict","model","template","replace","link","element","attrs","$","isArray","select","typeaheadSourceArray","typeaheadSource","split","length","tagsinput","options","typeahead","source","itemValue","itemvalue","itemText","itemtext","confirmKeys","confirmkeys","JSON","parse","tagClass","tagclass","i","on","event","indexOf","push","idx","splice","prev","slice","$watch","added","filter","removed"],"mappings":";;;;;AAAAA,QAAQC,OAAO,0BACdC,UAAU,sBAAuB,WAEhC,QAASC,GAAgBC,EAAOC,GAC9B,MAAKA,GAGDL,QAAQM,WAAWF,EAAMG,QAAQF,IAC5BD,EAAMG,QAAQF,GAEhB,SAASG,GACd,MAAOA,GAAKH,IANLI,OAUX,OACEC,SAAU,KACVN,OACEO,MAAO,YAETC,SAAU,6BACVC,SAAS,EACTC,KAAM,SAASV,EAAOW,EAASC,GAC7BC,EAAE,WACKjB,QAAQkB,QAAQd,EAAMO,SACzBP,EAAMO,SAER,IAAIQ,GAASF,EAAE,SAAUF,GACrBK,EAAuBJ,EAAMK,gBAAkBL,EAAMK,gBAAgBC,MAAM,KAAO,KAClFD,EAAkBD,EACjBA,EAAqBG,OAAS,EAC3BnB,EAAMG,QAAQa,EAAqB,IAAIA,EAAqB,IAC1DhB,EAAMG,QAAQa,EAAqB,IACvC,IAEND,GAAOK,UAAUpB,EAAMG,QAAQS,EAAMS,SAAW,MAC9CC,WACEC,OAAW3B,QAAQM,WAAWe,GAAmBA,EAAkB,MAErEO,UAAWzB,EAAgBC,EAAOY,EAAMa,WACxCC,SAAW3B,EAAgBC,EAAOY,EAAMe,UACxCC,YAAc7B,EAAgBC,EAAOY,EAAMiB,aAAeC,KAAKC,MAAMnB,EAAMiB,cAAgB,IAC3FG,SAAWpC,QAAQM,WAAWF,EAAMG,QAAQS,EAAMqB,WAAajC,EAAMG,QAAQS,EAAMqB,UAAY,WAAiB,MAAOrB,GAAMqB,WAG/H,KAAK,GAAIC,GAAI,EAAGA,EAAIlC,EAAMO,MAAMY,OAAQe,IACtCnB,EAAOK,UAAU,MAAOpB,EAAMO,MAAM2B,GAGtCnB,GAAOoB,GAAG,YAAa,SAASC,GACU,KAApCpC,EAAMO,MAAM8B,QAAQD,EAAMhC,OAC5BJ,EAAMO,MAAM+B,KAAKF,EAAMhC,QAG3BW,EAAOoB,GAAG,cAAe,SAASC,GAChC,GAAIG,GAAMvC,EAAMO,MAAM8B,QAAQD,EAAMhC,KACxB,MAARmC,GACFvC,EAAMO,MAAMiC,OAAOD,EAAK,IAK5B,IAAIE,GAAOzC,EAAMO,MAAMmC,OACvB1C,GAAM2C,OAAO,QAAS,WACpB,GAEIT,GAFAU,EAAQ5C,EAAMO,MAAMsC,OAAO,SAASX,GAAI,MAA2B,KAApBO,EAAKJ,QAAQH,KAC5DY,EAAUL,EAAKI,OAAO,SAASX,GAAI,MAAkC,KAA3BlC,EAAMO,MAAM8B,QAAQH,IAMlE,KAHAO,EAAOzC,EAAMO,MAAMmC,QAGdR,EAAI,EAAGA,EAAIY,EAAQ3B,OAAQe,IAC9BnB,EAAOK,UAAU,SAAU0B,EAAQZ,GAOrC,KAHAnB,EAAOK,UAAU,WAGZc,EAAI,EAAGA,EAAIU,EAAMzB,OAAQe,IAC5BnB,EAAOK,UAAU,MAAOwB,EAAMV,MAE/B"}
|
@@ -3,7 +3,7 @@ google.setOnLoadCallback(drawChart);
|
||||
|
||||
function drawChart() {
|
||||
googleLineChart('chart/home/account', 'accounts-chart');
|
||||
googleBarChart('chart/home/budgets', 'budgets-chart');
|
||||
googleColumnChart('chart/home/budgets', 'budgets-chart');
|
||||
googleColumnChart('chart/home/categories', 'categories-chart');
|
||||
googlePieChart('chart/home/bills', 'bills-chart');
|
||||
getBoxAmounts();
|
||||
|
@@ -5,14 +5,43 @@ $(function () {
|
||||
if (typeof(googleLineChart) === 'function' && typeof(piggyBankID) !== 'undefined') {
|
||||
googleLineChart('chart/piggy-history/' + piggyBankID, 'piggy-bank-history');
|
||||
}
|
||||
$('#sortable').sortable(
|
||||
|
||||
$('#sortable tbody').sortable(
|
||||
{
|
||||
helper: fixHelper,
|
||||
stop: stopSorting,
|
||||
handle: '.handle'
|
||||
handle: '.handle',
|
||||
start: function (event, ui) {
|
||||
// Build a placeholder cell that spans all the cells in the row
|
||||
var cellCount = 0;
|
||||
$('td, th', ui.helper).each(function () {
|
||||
// For each TD or TH try and get it's colspan attribute, and add that or 1 to the total
|
||||
var colspan = 1;
|
||||
var colspanAttr = $(this).attr('colspan');
|
||||
if (colspanAttr > 1) {
|
||||
colspan = colspanAttr;
|
||||
}
|
||||
cellCount += colspan;
|
||||
});
|
||||
|
||||
// Add the placeholder UI - note that this is the item's content, so TD rather than TR
|
||||
ui.placeholder.html('<td colspan="' + cellCount + '"> </td>');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Return a helper with preserved width of cells
|
||||
var fixHelper = function(e, tr) {
|
||||
var $originals = tr.children();
|
||||
var $helper = tr.clone();
|
||||
$helper.children().each(function (index) {
|
||||
// Set helper cell sizes to match the original sizes
|
||||
$(this).width($originals.eq(index).width());
|
||||
});
|
||||
return $helper;
|
||||
}
|
||||
|
||||
function addMoney(e) {
|
||||
var pigID = parseInt($(e.target).data('id'));
|
||||
$('#moneyManagementModal').empty().load('piggy-banks/add/' + pigID, function () {
|
||||
@@ -33,7 +62,7 @@ function removeMoney(e) {
|
||||
function stopSorting() {
|
||||
$('.loadSpin').addClass('fa fa-refresh fa-spin');
|
||||
var order = [];
|
||||
$.each($('#sortable>div'), function(i,v) {
|
||||
$.each($('#sortable>tbody>tr'), function(i,v) {
|
||||
var holder = $(v);
|
||||
var id = holder.data('id');
|
||||
order.push(id);
|
||||
|
@@ -1,112 +0,0 @@
|
||||
$(document).ready(function () {
|
||||
$('.relateTransaction').click(relateTransactionDialog);
|
||||
//$('.unrelate-checkbox').click(unrelateTransaction);
|
||||
|
||||
});
|
||||
|
||||
function unrelateTransaction(e) {
|
||||
var target = $(e.target);
|
||||
var id = target.data('id');
|
||||
var parent = target.data('parent');
|
||||
|
||||
if(typeof id == "undefined" && typeof parent == "undefined") {
|
||||
target = target.parent();
|
||||
id = target.data('id');
|
||||
parent = target.data('parent');
|
||||
}
|
||||
console.log('unlink ' + id + ' from ' + parent);
|
||||
|
||||
$.post('related/removeRelation/' + id + '/' + parent, {_token: token}).success(function (data) {
|
||||
target.parent().parent().remove();
|
||||
}).fail(function () {
|
||||
alert('Could not!');
|
||||
});
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
//$.post('related/removeRelation/' + id + '/' + relatedTo, {_token: token}).success(function (data) {
|
||||
// target.parent().parent().remove();
|
||||
//}).fail(function () {
|
||||
// alert('Could not!');
|
||||
//});
|
||||
|
||||
}
|
||||
|
||||
function relateTransactionDialog(e) {
|
||||
var target = $(e.target);
|
||||
var ID = target.data('id');
|
||||
|
||||
|
||||
$('#relationModal').empty().load('related/related/' + ID, function () {
|
||||
|
||||
$('#relationModal').modal('show');
|
||||
getAlreadyRelatedTransactions(e, ID);
|
||||
$('#searchRelated').submit(function (e) {
|
||||
searchRelatedTransactions(e, ID);
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function searchRelatedTransactions(e, ID) {
|
||||
var searchValue = $('#relatedSearchValue').val();
|
||||
if (searchValue != '') {
|
||||
$.post('related/search/' + ID, {searchValue: searchValue, _token: token}).success(function (data) {
|
||||
// post the results to some div.
|
||||
$('#relatedSearchResultsTitle').show();
|
||||
$('#relatedSearchResults').empty().html(data);
|
||||
// remove any clicks.
|
||||
$('.relate').unbind('click').on('click', doRelateNewTransaction);
|
||||
|
||||
}).fail(function () {
|
||||
alert('Could not search. Sorry.');
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function doRelateNewTransaction(e) {
|
||||
// remove the row from the table:
|
||||
var target = $(e.target);
|
||||
var id = target.data('id');
|
||||
var parent = target.data('parent');
|
||||
|
||||
if (typeof id == "undefined" && typeof parent == "undefined") {
|
||||
target = target.parent();
|
||||
console.log(target);
|
||||
id = target.data('id');
|
||||
parent = target.data('parent');
|
||||
}
|
||||
|
||||
console.log('Relate ' + id + ' to ' + parent);
|
||||
$.post('related/relate/' + parent + '/' + id, {_token: token}).success(function (data) {
|
||||
// success! remove entry:
|
||||
target.parent().parent().remove();
|
||||
// get related stuff (again).
|
||||
getAlreadyRelatedTransactions(null, parent);
|
||||
}).fail(function () {
|
||||
// could not relate.
|
||||
alert('Could not relate this transaction to the intended target.');
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function getAlreadyRelatedTransactions(e, ID) {
|
||||
//#alreadyRelated
|
||||
$.get('related/alreadyRelated/' + ID).success(function (data) {
|
||||
$('#alreadyRelated').empty().html(data);
|
||||
// some event triggers.
|
||||
$('.unrelate').unbind('click').on('click', unrelateTransaction);
|
||||
|
||||
}).fail(function () {
|
||||
alert('Cannot get related stuff.');
|
||||
});
|
||||
}
|
@@ -29,8 +29,8 @@ $(function() {
|
||||
var url = window.location;
|
||||
var element = $('ul.nav a').filter(function() {
|
||||
return this.href == url || url.href.indexOf(this.href) == 0;
|
||||
}).addClass('active').parent().parent().addClass('in').parent();
|
||||
}).parent().parent().addClass('in').parent();/*addClass('active')*/
|
||||
if (element.is('li')) {
|
||||
element.addClass('active');
|
||||
//element.addClass('active');
|
||||
}
|
||||
});
|
||||
|
115
public/js/tags.js
Normal file
115
public/js/tags.js
Normal file
@@ -0,0 +1,115 @@
|
||||
$(function () {
|
||||
|
||||
/*
|
||||
Hide and show the tag index help.
|
||||
*/
|
||||
$('#tagHelp').on('show.bs.collapse', function () {
|
||||
// set hideTagHelp = false
|
||||
$.post('/tags/hideTagHelp/false', {_token: token});
|
||||
$('#tagHelpButton').text('Hide help');
|
||||
|
||||
}).on('hide.bs.collapse', function () {
|
||||
// set hideTagHelp = true
|
||||
$.post('/tags/hideTagHelp/true', {_token: token});
|
||||
$('#tagHelpButton').text('Show help');
|
||||
|
||||
});
|
||||
|
||||
$('#clearLocation').click(clearLocation);
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
Some vars as prep for the map:
|
||||
*/
|
||||
var map;
|
||||
var markers = [];
|
||||
var setTag = false;
|
||||
|
||||
var mapOptions = {
|
||||
zoom: zoomLevel,
|
||||
center: new google.maps.LatLng(latitude, longitude),
|
||||
disableDefaultUI: true
|
||||
};
|
||||
|
||||
/*
|
||||
Clear location and reset zoomLevel.
|
||||
*/
|
||||
function clearLocation() {
|
||||
"use strict";
|
||||
deleteMarkers();
|
||||
$('input[name="latitude"]').val("");
|
||||
$('input[name="longitude"]').val("");
|
||||
$('input[name="zoomLevel"]').val("6");
|
||||
setTag = false;
|
||||
$('input[name="setTag"]').val('false');
|
||||
return false;
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
/*
|
||||
Create new map:
|
||||
*/
|
||||
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
|
||||
|
||||
/*
|
||||
Respond to click event.
|
||||
*/
|
||||
google.maps.event.addListener(map, 'rightclick', function (event) {
|
||||
placeMarker(event);
|
||||
});
|
||||
|
||||
/*
|
||||
Respond to zoom event.
|
||||
*/
|
||||
google.maps.event.addListener(map, 'zoom_changed', function () {
|
||||
saveZoomLevel(event);
|
||||
});
|
||||
/*
|
||||
Maybe place marker?
|
||||
*/
|
||||
if(doPlaceMarker) {
|
||||
var myLatlng = new google.maps.LatLng(latitude,longitude);
|
||||
var fakeEvent = {};
|
||||
fakeEvent.latLng = myLatlng;
|
||||
placeMarker(fakeEvent);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* save zoom level of map into hidden input.
|
||||
*/
|
||||
function saveZoomLevel() {
|
||||
"use strict";
|
||||
$('input[name="zoomLevel"]').val(map.getZoom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Place marker on map.
|
||||
* @param event
|
||||
*/
|
||||
function placeMarker(event) {
|
||||
deleteMarkers();
|
||||
var marker = new google.maps.Marker({position: event.latLng, map: map});
|
||||
$('input[name="latitude"]').val(event.latLng.lat());
|
||||
$('input[name="longitude"]').val(event.latLng.lng());
|
||||
markers.push(marker);
|
||||
setTag = true;
|
||||
$('input[name="setTag"]').val('true');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all markers in the array by removing references to them.
|
||||
*/
|
||||
function deleteMarkers() {
|
||||
for (var i = 0; i < markers.length; i++) {
|
||||
markers[i].setMap(null);
|
||||
}
|
||||
markers = [];
|
||||
}
|
||||
|
||||
|
||||
google.maps.event.addDomListener(window, 'load', initialize);
|
@@ -8,6 +8,20 @@ $(document).ready(function () {
|
||||
$('input[name="expense_account"]').typeahead({source: data});
|
||||
});
|
||||
}
|
||||
|
||||
if ($('input[name="tags"]').length > 0) {
|
||||
$.getJSON('json/tags').success(function (data) {
|
||||
var opt = {
|
||||
typeahead: {
|
||||
source: data
|
||||
}
|
||||
};
|
||||
$('input[name="tags"]').tagsinput(
|
||||
opt
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if ($('input[name="revenue_account"]').length > 0) {
|
||||
$.getJSON('json/revenue-accounts').success(function (data) {
|
||||
$('input[name="revenue_account"]').typeahead({source: data});
|
||||
|
61
resources/twig/accounts/create.twig
Normal file
61
resources/twig/accounts/create.twig
Normal file
@@ -0,0 +1,61 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, what) }}
|
||||
<form action="{{ route('accounts.store') }}" method="post" id="store" class="form-horizontal">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
|
||||
<input type="hidden" name="what" value="{{ what }}" />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{ subTitleIcon }}"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.text('name') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
|
||||
{% if what == 'asset' %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
{{ ExpandedForm.balance('openingBalance') }}
|
||||
{{ ExpandedForm.date('openingBalanceDate', phpdate('Y-m-d')) }}
|
||||
{{ ExpandedForm.select('accountRole', Config.get('firefly.accountRoles'),null,{'helpText' : 'Any extra options resulting from your choice can be set later.'}) }}
|
||||
{{ ExpandedForm.balance('virtualBalance') }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- panel for options -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.optionsList('create','account') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new {{ what }} account
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
36
resources/twig/accounts/delete.twig
Normal file
36
resources/twig/accounts/delete.twig
Normal file
@@ -0,0 +1,36 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute().getName(), account) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('accounts.destroy',account.id)}) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
Delete account "{{ account.name }}"
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Are you sure that you want to delete the {{account.accountType.type|lower}} "{{account.name}}"?
|
||||
</p>
|
||||
|
||||
{% if account.transactions|length > 0 %}
|
||||
<p class="text-danger">
|
||||
{{account.accountType.type|capitalize}} "{{ account.name }}" still has {{ account.transactions|length }} transaction(s) associated to it. These will be deleted as well.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if account.piggyBanks|length > 0 %}
|
||||
<p class="text-danger">
|
||||
{{account.accountType.type|capitalize}} "{{ account.name }}" still has {{ account.piggyBanks|length }} piggy bank(s) associated to it. These will be deleted as well.
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
<a href="{{URL.previous()}}" class="btn-default btn">Cancel</a >
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
71
resources/twig/accounts/edit.twig
Normal file
71
resources/twig/accounts/edit.twig
Normal file
@@ -0,0 +1,71 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute().getName(), account) }}
|
||||
{{ Form.model(account, {'class' : 'form-horizontal','id' : 'update','url' : route('accounts.update',account.id) } ) }}
|
||||
|
||||
<input type="hidden" name="id" value="{{account.id}}" />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{ subTitleIcon }}"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.text('name') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if account.accounttype.type == 'Default account' or account.accounttype.type == 'Asset account' %}
|
||||
{{ ExpandedForm.balance('openingBalance',null, {'currency' : openingBalance ? openingBalance.transactionCurrency : null}) }}
|
||||
{{ ExpandedForm.date('openingBalanceDate') }}
|
||||
{{ ExpandedForm.select('accountRole',Config.get('firefly.accountRoles')) }}
|
||||
{{ ExpandedForm.balance('virtualBalance',null) }}
|
||||
|
||||
{% endif %}
|
||||
{{ ExpandedForm.checkbox('active','1') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- panel for credit card options -->
|
||||
{% if Session.get('preFilled').accountRole == 'ccAsset' %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-credit-card"></i> Credit card options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.select('ccType',Config.get('firefly.ccTypes')) }}
|
||||
{{ ExpandedForm.date('ccMonthlyPaymentDate',null,{'helpText' : 'Select any year and any month, it will be ignored anway. Only the day of the month is relevant.'}) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- panel for options -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.optionsList('update','account') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
Update account
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,11 +1,11 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, what) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{{$subTitleIcon}}}"></i> {{{$subTitle}}}
|
||||
<i class="fa {{ subTitleIcon }}"></i> {{ subTitle}}
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="pull-right">
|
||||
@@ -15,27 +15,26 @@
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('accounts.create',$what)}}"><i class="fa fa-plus fa-fw"></i> New {{$what}} account</a></li>
|
||||
<li><a href="{{route('accounts.create', what)}}"><i class="fa fa-plus fa-fw"></i> New {{ what }} account</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@include('list.accounts')
|
||||
{% include 'list/accounts.twig' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
{% endblock %}
|
||||
|
||||
@section('styles')
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="css/bootstrap-sortable.css" type="text/css" media="all" />
|
||||
@stop
|
||||
{% endblock %}
|
||||
|
||||
@section('scripts')
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var what = '{{{$what}}}';
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
var what = '{{ what }}';
|
||||
</script>
|
||||
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
@@ -44,4 +43,4 @@
|
||||
<script type="text/javascript" src="js/gcharts.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap-sortable.js"></script>
|
||||
<script type="text/javascript" src="js/accounts.js"></script>
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,11 +1,11 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!}
|
||||
<div class="row">
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, account) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}}
|
||||
<i class="fa fa-fw {{ subTitleIcon }} fa-fw"></i> {{ account.name }}
|
||||
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
@@ -16,8 +16,8 @@
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('accounts.edit',$account->id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
|
||||
<li><a href="{{route('accounts.delete',$account->id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
|
||||
<li><a href="{{route('accounts.edit', account.id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
|
||||
<li><a href="{{route('accounts.delete', account.id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,19 +37,18 @@
|
||||
<i class="fa fa-repeat fa-fw"></i> Transactions
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.journals-full',['sorting' => true])
|
||||
{% include 'list/journals.twig' with {sorting:true} %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var accountID = {{{$account->id}}};
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
var token = "{{csrf_token()}}";
|
||||
var accountID = {{ account.id }};
|
||||
</script>
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
@@ -57,4 +56,5 @@
|
||||
<script type="text/javascript" src="js/gcharts.js"></script>
|
||||
<script src="js/jquery-ui.min.js" type="text/javascript"></script>
|
||||
<script src="js/accounts.js" type="text/javascript"></script>
|
||||
@stop
|
||||
|
||||
{% endblock %}
|
@@ -1,16 +1,17 @@
|
||||
@extends('layouts.guest')
|
||||
@section('content')
|
||||
{% extends "./layout/guest.twig" %}
|
||||
|
||||
@if($errors->has('email'))
|
||||
{% block content %}
|
||||
|
||||
{% if errors.has('email') %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<strong>Error!</strong> {{$errors->get('email')[0]}}
|
||||
<strong>Error!</strong> {{ errors.get('email')[0] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="row">
|
||||
@@ -42,9 +43,9 @@
|
||||
<button type="submit" class="btn btn-lg btn-success btn-block">Login</button>
|
||||
</p>
|
||||
<div class="btn-group btn-group-justified btn-group-sm">
|
||||
@if(Config::get('auth.allow_register') === true)
|
||||
<a href="{{route('register')}}" class="btn btn-default">Register</a>
|
||||
@endif
|
||||
{% if Config.get('auth.allow_register') %}
|
||||
<a href="{{ route('register') }}" class="btn btn-default">Register</a>
|
||||
{% endif %}
|
||||
<a href="/password/email" class="btn btn-default">Forgot your password?</a>
|
||||
</div>
|
||||
</form>
|
||||
@@ -52,4 +53,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
{% endblock %}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.guest')
|
||||
{% extends "./layout/guest.twig" %}
|
||||
|
||||
@section('content')
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="login-panel panel panel-default">
|
||||
@@ -8,28 +8,28 @@
|
||||
<h3 class="panel-title">Firefly III — Reset Password</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@if (session('status'))
|
||||
{% if session.status %}
|
||||
<div class="alert alert-success">
|
||||
{{ session('status') }}
|
||||
{{ session.status }}
|
||||
</div>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
@if (count($errors) > 0)
|
||||
{% if errors|length > 0 %}
|
||||
<div class="alert alert-danger">
|
||||
<strong>Whoops!</strong> There were some problems with your input.<br><br>
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
{% for error in errors.all %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
<form role="form" method="POST" action="/password/email">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
<div class="form-group">
|
||||
<label class="control-label">E-Mail</label>
|
||||
<input type="email" class="form-control" placeholder="E-Mail" name="email" value="{{ old('email') }}">
|
||||
<input type="email" class="form-control" placeholder="E-Mail" name="email" value="{{ old.email }}">
|
||||
</div>
|
||||
|
||||
<p>
|
||||
@@ -42,4 +42,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
{% endblock %}
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.guest')
|
||||
{% extends "./layout/guest.twig" %}
|
||||
|
||||
@section('content')
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="login-panel panel panel-default">
|
||||
@@ -11,23 +11,23 @@
|
||||
<p>
|
||||
Registering an account on Firefly requires an e-mail address.
|
||||
</p>
|
||||
@if (count($errors) > 0)
|
||||
{% if errors|length > 0 %}
|
||||
<div class="alert alert-danger">
|
||||
<strong>Whoops!</strong> There were some problems with your input.<br><br>
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
{% for error in errors.all %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
<form role="form" id="register" method="POST" action="/auth/register">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label">E-Mail</label>
|
||||
<input type="email" class="form-control" placeholder="E-Mail" name="email" value="{{ old('email') }}">
|
||||
<input type="email" class="form-control" placeholder="E-Mail" name="email" value="{{ old.email }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -55,5 +55,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
{% endblock %}
|
@@ -1,7 +1,7 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('bills.store')]) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, piggyBank) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'store','url' : route('bills.store')}) }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
@@ -11,19 +11,15 @@
|
||||
<i class="fa fa-exclamation-circle"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::text('name') !!}
|
||||
{!! ExpandedForm::tags('match') !!}
|
||||
{!! ExpandedForm::amount('amount_min') !!}
|
||||
{!! ExpandedForm::amount('amount_max') !!}
|
||||
{!! ExpandedForm::date('date',Carbon\Carbon::now()->addDay()->format('Y-m-d')) !!}
|
||||
{!! ExpandedForm::select('repeat_freq',$periods,'monthly') !!}
|
||||
{{ ExpandedForm.text('name') }}
|
||||
{{ ExpandedForm.tags('match') }}
|
||||
{{ ExpandedForm.amount('amount_min') }}
|
||||
{{ ExpandedForm.amount('amount_max') }}
|
||||
{{ ExpandedForm.date('date',phpdate('Y-m-d')) }}
|
||||
{{ ExpandedForm.select('repeat_freq',periods,'monthly') }}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new bill
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<!-- panel for optional fields -->
|
||||
@@ -32,9 +28,9 @@
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::integer('skip',0) !!}
|
||||
{!! ExpandedForm::checkbox('automatch',1,true) !!}
|
||||
{!! ExpandedForm::checkbox('active',1,true) !!}
|
||||
{{ ExpandedForm.integer('skip',0) }}
|
||||
{{ ExpandedForm.checkbox('automatch',1,true) }}
|
||||
{{ ExpandedForm.checkbox('active',1,true) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,20 +40,30 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('create','bill') !!}
|
||||
{{ ExpandedForm.optionsList('create','bill') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new bill
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@stop
|
||||
@section('styles')
|
||||
{% block styles %}
|
||||
<link href="css/bootstrap-tagsinput.css" type="text/css" rel="stylesheet" media="all">
|
||||
@stop
|
||||
@section('scripts')
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="js/bootstrap-tagsinput.min.js"></script>
|
||||
@stop
|
||||
{% endblock %}
|
32
resources/twig/bills/delete.twig
Normal file
32
resources/twig/bills/delete.twig
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, bill) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('bills.destroy',bill.id)}) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
Delete bill "{{ bill.name }}"
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Are you sure that you want to delete bill "{{ bill.name }}"?
|
||||
</p>
|
||||
|
||||
{% if bill.transactionjournals|length > 0 %}
|
||||
<p class="text-info">
|
||||
Bill "{{ bill.name }}" still has {{ bill.transactionjournals|length }} transactions connected
|
||||
to it. These will <strong>not</strong> be removed but will lose their connection to this bill.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
<a href="{{ URL.previous() }}" class="btn-default btn">Cancel</a >
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,43 +1,37 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $bill) !!}
|
||||
{!! Form::model($bill, ['class' => 'form-horizontal','id' => 'update','url' => route('bills.update', $bill->id)]) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, bill) }}
|
||||
{{ Form.model(bill, {'class' : 'form-horizontal','id' : 'update','url' : route('bills.update', bill.id)}) }}
|
||||
|
||||
<input type="hidden" name="id" value="{{$bill->id}}" />
|
||||
<input type="hidden" name="id" value="{{bill.id}}" />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<!-- panel for mandatory fields -->
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-exclamation-circle"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::text('name') !!}
|
||||
{!! ExpandedForm::tags('match') !!}
|
||||
{!! ExpandedForm::amount('amount_min') !!}
|
||||
{!! ExpandedForm::amount('amount_max') !!}
|
||||
{!! ExpandedForm::date('date',$bill->date->format('Y-m-d')) !!}
|
||||
{!! ExpandedForm::select('repeat_freq',$periods) !!}
|
||||
{{ ExpandedForm.text('name') }}
|
||||
{{ ExpandedForm.tags('match') }}
|
||||
{{ ExpandedForm.amount('amount_min') }}
|
||||
{{ ExpandedForm.amount('amount_max') }}
|
||||
{{ ExpandedForm.date('date',bill.date.format('Y-m-d')) }}
|
||||
{{ ExpandedForm.select('repeat_freq',periods) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Update bill
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<!-- panel for optional fields -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::integer('skip') !!}
|
||||
{!! ExpandedForm::checkbox('automatch',1) !!}
|
||||
{!! ExpandedForm::checkbox('active',1) !!}
|
||||
{{ ExpandedForm.integer('skip') }}
|
||||
{{ ExpandedForm.checkbox('automatch',1) }}
|
||||
{{ ExpandedForm.checkbox('active',1) }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,19 +40,27 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('update','bill') !!}
|
||||
{{ ExpandedForm.optionsList('update','bill') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Update bill
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@stop
|
||||
@section('styles')
|
||||
{% endblock %}
|
||||
{% block styles %}
|
||||
<link href="css/bootstrap-tagsinput.css" type="text/css" rel="stylesheet" media="all">
|
||||
@stop
|
||||
@section('scripts')
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="js/bootstrap-tagsinput.min.js"></script>
|
||||
@stop
|
||||
{% endblock %}
|
27
resources/twig/bills/index.twig
Normal file
27
resources/twig/bills/index.twig
Normal file
@@ -0,0 +1,27 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, piggyBank) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-sm-12 col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{ mainTitleIcon }}"></i> {{ title }}
|
||||
|
||||
<!-- 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('bills.create')}}"><i class="fa fa-plus fa-fw"></i> New bill</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'list/bills.twig' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@@ -1,25 +1,24 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $bill) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, bill) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-sm-12 col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-rotate-right"></i> {{{$bill->name}}}
|
||||
<i class="fa fa-rotate-right"></i> {{ bill.name }}
|
||||
|
||||
@if($bill->active)
|
||||
{% if bill.active %}
|
||||
<i class="fa fa-check fa-fw" title="Active"></i>
|
||||
@else
|
||||
{% else %}
|
||||
<i class="fa fa-times fa-fw" title="Inactive"></i>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
@if($bill->automatch)
|
||||
{% if bill.automatch %}
|
||||
<i class="fa fa-check fa-fw" title="Automatically matched by Firefly"></i>
|
||||
@else
|
||||
{% else %}
|
||||
<i class="fa fa-times fa-fw" title="Not automatically matched by Firefly"></i>
|
||||
@endif
|
||||
{% 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">
|
||||
@@ -27,8 +26,8 @@
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('bills.edit',$bill->id)}}"><i class="fa fa-fw fa-pencil"></i> edit</a></li>
|
||||
<li><a href="{{route('bills.delete',$bill->id)}}"><i class="fa fa-fw fa-trash-o"></i> delete</a></li>
|
||||
<li><a href="{{route('bills.edit',bill.id)}}"><i class="fa fa-fw fa-pencil"></i> edit</a></li>
|
||||
<li><a href="{{route('bills.delete',bill.id)}}"><i class="fa fa-fw fa-trash-o"></i> delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,21 +38,21 @@
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
Matching on
|
||||
@foreach(explode(',',$bill->match) as $word)
|
||||
<span class="label label-info">{{{$word}}}</span>
|
||||
@endforeach
|
||||
between {!! Amount::format($bill->amount_min) !!} and {!! Amount::format($bill->amount_max) !!}.
|
||||
Repeats {!! $bill->repeat_freq !!}.</td>
|
||||
{% for word in bill.match|split(',') %}
|
||||
<span class="label label-info">{{ word }}</span>
|
||||
{% endfor %}
|
||||
between {{ bill.amount_min|formatAmount }} and {{ bill.amount_max|formatAmount }}.
|
||||
Repeats {{ bill.repeat_freq }}.</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Next expected match</td>
|
||||
<td>
|
||||
@if($bill->nextExpectedMatch)
|
||||
{{$bill->nextExpectedMatch->format('j F Y')}}
|
||||
@else
|
||||
{% if bill.nextExpectedMatch %}
|
||||
{{bill.nextExpectedMatch.format('j F Y')}}
|
||||
{% else %}
|
||||
<em>Unknown</em>
|
||||
@endif
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -67,7 +66,7 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<a href="{{route('bills.rescan',$bill->id)}}" class="btn btn-default">Rescan old transactions</a>
|
||||
<a href="{{route('bills.rescan',bill.id)}}" class="btn btn-default">Rescan old transactions</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,23 +93,21 @@
|
||||
Connected transaction journals
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.journals-full',['sorting' => false])
|
||||
{% include 'list/journals' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
{% endblock %}
|
||||
|
||||
@section('scripts')
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var billID = {{{$bill->id}}};
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
var billID = {{ bill.id }};
|
||||
</script>
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript" src="js/gcharts.options.js"></script>
|
||||
<script type="text/javascript" src="js/gcharts.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/bills.js"></script>
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,7 +1,7 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('budgets.store')]) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'store','url' : route('budgets.store')}) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
@@ -9,15 +9,9 @@
|
||||
<i class="fa fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::text('name') !!}
|
||||
{{ ExpandedForm.text('name') }}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new budget
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<!-- panel for options -->
|
||||
@@ -26,17 +20,26 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('create','budget') !!}
|
||||
{{ ExpandedForm.optionsList('create','budget') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new budget
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{!! Form::close() !!}
|
||||
</form>
|
||||
|
||||
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,28 +1,28 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $budget) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('budgets.destroy',$budget->id)]) !!}
|
||||
<div class="row">
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, budget) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('budgets.destroy',budget.id) }) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
Delete budget "{{{$budget->name}}}"
|
||||
Delete budget "{{ budget.name}}"
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Are you sure that you want to delete budget "{{{$budget->name}}}"?
|
||||
Are you sure that you want to delete budget "{{ budget.name }}"?
|
||||
</p>
|
||||
|
||||
@if($budget->transactionjournals()->count() > 0)
|
||||
{% if budget.transactionjournals|length > 0 %}
|
||||
<p class="text-info">
|
||||
Budget "{{{$budget->name}}}" still has {{$budget->transactionjournals()->count()}} transactions connected
|
||||
Budget "{{ budget.name }}" still has {{ budget.transactionjournals|length }} transactions connected
|
||||
to it. These will <strong>not</strong> be removed but will lose their connection to this budget.
|
||||
</p>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
<a href="{{URL::previous()}}" class="btn-default btn">Cancel</a >
|
||||
<a href="{{URL.previous()}}" class="btn-default btn">Cancel</a >
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,6 +39,5 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!! Form::close() !!}
|
||||
@stop
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,14 +1,14 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $budget) !!}
|
||||
<div class="row">
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, budget) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Use budgets to organize and limit your expenses.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::model($budget, ['class' => 'form-horizontal','id' => 'update','url' => route('budgets.update',$budget->id)]) !!}
|
||||
<input type="hidden" name="id" value="{{$budget->id}}" />
|
||||
{{ Form.model(budget, {'class' : 'form-horizontal','id' : 'update','url' : route('budgets.update',budget.id) } ) }}
|
||||
<input type="hidden" name="id" value="{{budget.id}}" />
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<div class="panel panel-primary">
|
||||
@@ -16,15 +16,11 @@
|
||||
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::checkbox('active') !!}
|
||||
{!! ExpandedForm::text('name') !!}
|
||||
{{ ExpandedForm.checkbox('active') }}
|
||||
{{ ExpandedForm.text('name') }}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-pencil"></i> Update budget
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<!-- panel for options -->
|
||||
@@ -33,12 +29,21 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('update','budget') !!}
|
||||
{{ ExpandedForm.optionsList('update','budget') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-pencil"></i> Update budget
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,16 +1,16 @@
|
||||
<form style="display: inline;" id="income" action="{{route('budgets.postIncome')}}" method="POST">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}"
|
||||
|
||||
{!! Form::token() !!}
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<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" id="myModalLabel">Update (expected) available amount for {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}</h4>
|
||||
<h4 class="modal-title" id="myModalLabel">Update (expected) available amount for {{Session.get('start').format('F Y')}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">€</div>
|
||||
<input step="any" class="form-control" id="amount" value="{{$amount->data}}" autocomplete="off" name="amount" type="number">
|
||||
<div class="input-group-addon">{{ getCurrencySymbol() }}</div>
|
||||
<input step="any" class="form-control" id="amount" value="{{ amount.data }}" autocomplete="off" name="amount" type="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
192
resources/twig/budgets/index.twig
Normal file
192
resources/twig/budgets/index.twig
Normal file
@@ -0,0 +1,192 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-sm-8 col-md-8">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-calendar fa-fw"></i>
|
||||
{{ Session.get('start').format('F Y') }}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-4 col-sm-3">
|
||||
<small>Budgeted: <span id="budgetedAmount" data-value="300"></span></small>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
|
||||
<small>Available in {{ Session.get('start').format('F Y') }}:
|
||||
<a href="#" class="updateIncome"><span id="totalAmount" data-value="{{ amount }}">{{ amount|formatAmount }}</span></a></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-bar progress-bar-info" id="progress-bar-default" role="progressbar" aria-valuenow="0" aria-valuemin="0"
|
||||
aria-valuemax="100" style="width: 0;"></div>
|
||||
<div class="progress-bar progress-bar-danger" id="progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0"
|
||||
aria-valuemax="100" style="width: 0;"></div>
|
||||
<div class="progress-bar progress-bar-warning" id="progress-bar-warning" role="progressbar" aria-valuenow="10" aria-valuemin="0"
|
||||
aria-valuemax="100" style="width: 0;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-4 col-sm-3">
|
||||
<small>Spent: {{ spent|formatAmount }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="progress progress-striped">
|
||||
{% if overspent %}
|
||||
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="{{ spentPCT }}" aria-valuemin="0"
|
||||
aria-valuemax="100" style="width: {{ spentPCT }}%;"></div>
|
||||
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{ 100-spentPCT }}" aria-valuemin="0"
|
||||
aria-valuemax="100" style="width: {{ 100-spentPCT }}%;"></div>
|
||||
{% else %}
|
||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{ spentPCT }}" aria-valuemin="0"
|
||||
aria-valuemax="100" style="width: {{ spentPCT }}%;"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-4 col-md-4">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-tags"></i>
|
||||
Transactions without a budget
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<a href="{{ route('budgets.noBudget') }}">Transactions without a budget in
|
||||
{{ Session.get('start').format('F Y') }}.</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{% for budget in budgets %}
|
||||
<div class="col-lg-3 col-sm-4 col-md-6" style="height:180px;">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-tasks"></i>
|
||||
{% if budget.currentRep %}
|
||||
<a href="{{ route('budgets.show', [budget.id, budget.currentRep.id]) }}" id="budget-link-{{ budget.id }}">{{ budget.name }}</a>
|
||||
{% else %}
|
||||
<a href="{{ route('budgets.show',budget.id) }}" id="budget-link-{{ budget.id }}">{{ budget.name }}</a>
|
||||
{% 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('budgets.edit',budget.id) }}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
|
||||
<li><a href="{{ route('budgets.delete',budget.id) }}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<!-- the range in which the budget can be set -->
|
||||
<p>
|
||||
{% if budget.currentRep %}
|
||||
<input type="range" data-id="{{ budget.id }}" data-spent="{{ budget.spent }}" id="budget-range-{{ budget.id }}"
|
||||
max="{{ budgetMaximum }}" min="0" value="{{ budget.currentRep.amount }}"/>
|
||||
{% else %}
|
||||
<input type="range" data-id="{{ budget.id }}" data-spent="{{ budget.spent }}" id="budget-range-{{ budget.id }}"
|
||||
max="{{ budgetMaximum }}" min="0" value="0"/>
|
||||
{% endif %}
|
||||
</p>
|
||||
<!-- some textual info about the budget. Updates dynamically. -->
|
||||
<p>
|
||||
<!-- budget-holder-X holds all the elements -->
|
||||
<span id="budget-holder-{{ budget.id }}">
|
||||
{% if budget.currentRep %}
|
||||
<!-- budget-description-X holds the description. -->
|
||||
<span id="budget-description-{{ budget.id }}">Budgeted: </span>
|
||||
<!-- budget-info-X holds the input and the euro-sign: -->
|
||||
<span id="budget-info-{{ budget.id }}">
|
||||
{% if budget.currentRep.amount > budget.spent %}
|
||||
<span class="text-success">{{ getCurrencySymbol() }}</span> <input type="number" min="0" max="{{ budgetMaximum }}" data-id="{{ budget.id }}"
|
||||
step="1" value="{{ budget.currentRep.amount }}"
|
||||
style="width:90px;color:#3c763d;"/>
|
||||
{% else %}
|
||||
<span class="text-danger">{{ getCurrencySymbol() }}</span> <input type="number" min="0" max="{{ budgetMaximum }}" data-id="{{ budget.id }}"
|
||||
step="1" value="{{ budget.currentRep.amount }}"
|
||||
style="width:90px;color:#a94442;"/>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span id="budget-description-{{ budget.id }}"><em>No budget</em></span>
|
||||
<span id="budget-info-{{ budget.id }}">
|
||||
<span class="text-success" style="display:none;">{{ Amount.getCurrencySymbol() }}</span> <input data-id="{{ budget.id }}" type="number"
|
||||
min="0" max="{{ budgetMaximum }}" step="1"
|
||||
value="0"
|
||||
style="width:50px;color:#3c763d;display:none;"/>
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<span id="spent-{{ budget.id }}" data-value="{{ budget.spent }}">Spent: {{ budget.spent|formatAmount }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="col-lg-3 col-sm-4 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-plus-circle"></i>
|
||||
Create budget
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<a href="{{ route('budgets.create') }}" class="btn btn-success"><i class="fa fa-fw fa-plus"></i> Create new budget</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if inactive|length > 0 %}
|
||||
<div class="col-lg-3 col-sm-4 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-minus-circle"></i>
|
||||
Inactive budgets
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% for index,budget in inactive %}
|
||||
{% if index != inactive|length-1 %}
|
||||
<a href="{{ route('budgets.show',budget.id) }}">{{ budget.name }}</a>,
|
||||
{% else %}
|
||||
<a href="{{ route('budgets.show',budget.id) }}">{{ budget.name }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- DIALOG -->
|
||||
<div class="modal fade" id="monthlyBudgetModal">
|
||||
</div><!-- /.modal -->
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="js/budgets.js"></script>
|
||||
{% endblock %}
|
@@ -1,18 +1,17 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, subTitle) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
{{{$subTitle}}}
|
||||
{{ subTitle }}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.journals-full',['journals' => $list,'sorting' => false])
|
||||
{% include 'list/journals.twig' with {'journals': list} %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
{% endblock %}
|
107
resources/twig/budgets/show.twig
Normal file
107
resources/twig/budgets/show.twig
Normal file
@@ -0,0 +1,107 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName,budget, repetition) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-md-9 col-sm-7">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Overview
|
||||
|
||||
|
||||
<!-- 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('budgets.edit',budget.id) }}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
|
||||
<li><a href="{{ route('budgets.delete',budget.id) }}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="budgetOverview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Transactions
|
||||
</div>
|
||||
{% include 'list/journals.twig' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-3 col-sm-5">
|
||||
{% if limits|length == 1 %}
|
||||
<p class="small text-center"><a href="{{ route('budgets.show',budget.id) }}">Show everything</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% for limit in limits %}
|
||||
{% for rep in limit.limitRepetitions %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="{{route('budgets.show',[budget.id,rep.id])}}">{{rep.startdate.format('F Y')}}</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||
Amount: {{ rep.amount|formatAmount }}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||
Spent: {{ spentInRepetition(rep)|formatAmount }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
{% set overspent = spentInRepetition(rep) > rep.amount %}
|
||||
{% if overspent %}
|
||||
{% set spent = spentInRepetition(rep) %}
|
||||
{% set pct = (spent != 0 ? (rep.amount / spent)*100 : 0) %}
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{pct|round}}" aria-valuemin="0" aria-valuemax="100" style="width: {{pct|round}}%;"></div>
|
||||
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{(100-pct)|round}}" aria-valuemin="0" aria-valuemax="100" style="width: {{(100-pct)|round}}%;"></div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% set amount = rep.amount %}
|
||||
{% set pct = (amount != 0 ? (spentInRepetition(rep) / amount)*100 : 0) %}
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{pct|round}}" aria-valuemin="0" aria-valuemax="100" style="width: {{pct|round}}%;"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% if limits|length == 1 %}
|
||||
<p class="small text-center"><a href="{{route('budgets.show',budget.id)}}">Show everything</a></p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var budgetID = {{budget.id}};
|
||||
{% if repetition.id %}
|
||||
var repetitionID = {{repetition.id}};
|
||||
var year = {{repetition.startdate.format('Y')}};
|
||||
{% else %}
|
||||
var year = {{Session.get('start').format('Y')}};
|
||||
{% endif %}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript" src="js/gcharts.options.js"></script>
|
||||
<script type="text/javascript" src="js/gcharts.js"></script>
|
||||
<script type="text/javascript" src="js/budgets.js"></script>
|
||||
|
||||
{% endblock %}
|
@@ -1,7 +1,7 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('categories.store')]) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'store','url' : route('categories.store')}) }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
@@ -10,14 +10,9 @@
|
||||
<i class="fa fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::text('name') !!}
|
||||
{{ ExpandedForm.text('name') }}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new category
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
@@ -28,14 +23,23 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('create','category') !!}
|
||||
{{ ExpandedForm.optionsList('create','category') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new category
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@stop
|
@@ -1,34 +1,33 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $category) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('categories.destroy',$category->id)]) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, category) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('categories.destroy',category.id)}) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
Delete category "{{{$category->name}}}"
|
||||
Delete category "{{ category.name }}"
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Are you sure that you want to delete category "{{$category->name}}"?
|
||||
Are you sure that you want to delete category "{{ category.name }}"?
|
||||
</p>
|
||||
|
||||
@if($category->transactionjournals()->count() > 0)
|
||||
{% if category.transactionjournals|length > 0 %}
|
||||
<p class="text-info">
|
||||
Category "{{{$category->name}}}" still has {{$category->transactionjournals()->count()}} transactions connected
|
||||
Category "{{ category.name }}" still has {{ category.transactionjournals|length }} transactions connected
|
||||
to it. These will <strong>not</strong> be removed but will lose their connection to this category.
|
||||
</p>
|
||||
@endif
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
<a href="{{URL::previous()}}" class="btn-default btn">Cancel</a >
|
||||
<a href="{{ URL.previous() }}" class="btn-default btn">Cancel</a >
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!! Form::close()!!}
|
||||
@stop
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,8 +1,8 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $category) !!}
|
||||
{!! Form::model($category, ['class' => 'form-horizontal','id' => 'update','url' => route('categories.update',$category->id)]) !!}
|
||||
<input type="hidden" name="id" value="{{$category->id}}" />
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, category) }}
|
||||
{{ Form.model(category, {'class' : 'form-horizontal','id' : 'update','url' : route('categories.update',category.id)}) }}
|
||||
<input type="hidden" name="id" value="{{ category.id }}" />
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
@@ -10,14 +10,10 @@
|
||||
<i class="fa fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::text('name') !!}
|
||||
{{ ExpandedForm.text('name') }}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
Update category
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
|
||||
@@ -28,12 +24,21 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('update','category') !!}
|
||||
{{ ExpandedForm.optionsList('update','category') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
Update category
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
@stop
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,11 +1,11 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{{$mainTitleIcon}}}"></i> Categories
|
||||
<i class="fa {{ mainTitleIcon }}"></i> Categories
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="pull-right">
|
||||
@@ -15,30 +15,26 @@
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('categories.create')}}"><i class="fa fa-plus fa-fw"></i> New category</a></li>
|
||||
<li><a href="{{ route('categories.create') }}"><i class="fa fa-plus fa-fw"></i> New category</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@include('list.categories')
|
||||
{% include 'list/categories.twig' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
@section('styles')
|
||||
{% endblock %}
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="css/bootstrap-sortable.css" type="text/css" media="all" />
|
||||
@stop
|
||||
{% endblock %}
|
||||
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
</script>
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript" src="js/gcharts.options.js"></script>
|
||||
<script type="text/javascript" src="js/gcharts.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap-sortable.js"></script>
|
||||
<script type="text/javascript" src="js/categories.js"></script>
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,18 +1,18 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, subTitle) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
{{{$subTitle}}}
|
||||
{{ subTitle }}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.journals-full',['journals' => $list,'sorting' => false])
|
||||
{% include 'list/journals.twig' with {'journals': list} %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $category) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, category) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
@@ -34,17 +34,16 @@
|
||||
Transactions
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.journals-full',['sorting' => false])
|
||||
{% include 'list/journals' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
var categoryID = {{$category->id}};
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
var categoryID = {{ category.id }};
|
||||
</script>
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
@@ -52,4 +51,4 @@
|
||||
<script type="text/javascript" src="js/gcharts.js"></script>
|
||||
<script type="text/javascript" src="js/categories.js"></script>
|
||||
|
||||
@stop
|
||||
{% endblock %}
|
@@ -1,24 +1,20 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'store','route' => 'currency.store']) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'store','route' : 'currency.store'}) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{{$subTitleIcon}}}"></i> Mandatory fields
|
||||
<i class="fa {{ subTitleIcon }}"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::text('name',null,['maxlength' => 48]) !!}
|
||||
{!! ExpandedForm::text('symbol',null,['maxlength' => 8]) !!}
|
||||
{!! ExpandedForm::text('code',null,['maxlength' => 3]) !!}
|
||||
{{ ExpandedForm.text('name',null,{'maxlength' : 48}) }}
|
||||
{{ ExpandedForm.text('symbol',null,{'maxlength': 8}) }}
|
||||
{{ ExpandedForm.text('code',null,{'maxlength' : 3}) }}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new currency
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
@@ -29,12 +25,20 @@
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! ExpandedForm::optionsList('create','currency') !!}
|
||||
{{ ExpandedForm.optionsList('create','currency') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
@stop
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new currency
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,25 +1,26 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $currency) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('currency.destroy',$currency->id)]) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, currency) }}
|
||||
{{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('currency.destroy',currency.id)}) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
Delete currency "{{{$currency->name}}}"
|
||||
Delete currency "{{ currency.name }}"
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Are you sure that you want to delete currency "{{{$currency->name}}}"?
|
||||
Are you sure that you want to delete currency "{{ currency.name }}"?
|
||||
</p>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
<a href="{{URL::previous()}}" class="btn-default btn">Cancel</a >
|
||||
<a href="{{ URL.previous }}" class="btn-default btn">Cancel</a >
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
@stop
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
45
resources/twig/currency/edit.twig
Normal file
45
resources/twig/currency/edit.twig
Normal file
@@ -0,0 +1,45 @@
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, currency) }}
|
||||
{{ Form.model(currency, {'class' : 'form-horizontal','id' : 'update','url' : route('currency.update',currency.id)}) }}
|
||||
|
||||
<input type="hidden" name="id" value="{{currency.id}}" />
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{ subTitleIcon }}"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.text('name',null,{'maxlength' : 48}) }}
|
||||
{{ ExpandedForm.text('symbol',null,{'maxlength' : 8}) }}
|
||||
{{ ExpandedForm.text('code',null,{'maxlength' : 3}) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
|
||||
<!-- panel for options -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ ExpandedForm.optionsList('update','currency') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Update currency
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{% extends "./layout/default.twig" %}
|
||||
{% block content %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-sm-12 col-md-12">
|
||||
@@ -13,37 +13,37 @@
|
||||
Firefly III supports various currencies which you can set and enable here.
|
||||
</p>
|
||||
<ul>
|
||||
@if(count($currencies) > 0)
|
||||
{% if currencies|length > 0 %}
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th colspan="2">Currency</th>
|
||||
</tr>
|
||||
@foreach($currencies as $currency)
|
||||
{% for currency in currencies %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a class="btn btn-default" href="{{route('currency.edit',$currency->id)}}"><i class="fa fa-fw fa-pencil"></i></a>
|
||||
<a class="btn btn-default" href="{{route('currency.delete',$currency->id)}}"><i class="fa fa-fw fa-trash"></i></a>
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a class="btn btn-default" href="{{route('currency.edit',currency.id)}}"><i class="fa fa-fw fa-pencil"></i></a>
|
||||
<a class="btn btn-default" href="{{route('currency.delete',currency.id)}}"><i class="fa fa-fw fa-trash"></i></a>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{{$currency->name}}} ({{{$currency->code}}}) ({{{$currency->symbol}}})</td>
|
||||
<td>{{ currency.name }} ({{ currency.code }}) ({{ currency.symbol|raw }})</td>
|
||||
<td>
|
||||
@if($currency->id == $defaultCurrency->id)
|
||||
{% if currency.id == defaultCurrency.id %}
|
||||
<span class="label label-success">default</span>
|
||||
@else
|
||||
<a class="btn btn-info" href="{{route('currency.default',$currency->id)}}">make default</a>
|
||||
@endif
|
||||
{% else %}
|
||||
<a class="btn btn-info btn-xs" href="{{route('currency.default',currency.id)}}">make default</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@endforeach
|
||||
{% endfor %}
|
||||
</table>
|
||||
@endif
|
||||
{% endif %}
|
||||
<p><a class="btn btn-success" href="{{route('currency.create')}}"><i class="fa fa-fw fa-plus-circle"></i> Add another currency</a></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
{% endblock %}
|
1
resources/twig/emails/password.twig
Normal file
1
resources/twig/emails/password.twig
Normal file
@@ -0,0 +1 @@
|
||||
Click here to reset your password: {{ url('password/reset/' . token) }}
|
@@ -1,5 +1,7 @@
|
||||
@extends('layouts.guest')
|
||||
@section('content')
|
||||
{% extends "./layout/guest.twig" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h1 class="text-danger">Firefly<br/>
|
||||
@@ -10,7 +12,7 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
{{$message or 'General unknown errror'}}
|
||||
{{ message |default('General unknown errror') }}
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
{% endblock %}
|
23
resources/twig/form/amount.twig
Normal file
23
resources/twig/form/amount.twig
Normal file
@@ -0,0 +1,23 @@
|
||||
<div class="{{ classes }}">
|
||||
<label for="{{ options.id }}" class="col-sm-4 control-label">{{ label }}</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle amountCurrencyDropdown" data-toggle="dropdown" aria-expanded="false">
|
||||
<span id="amountCurrentSymbol">{{ defaultCurrency.symbol|raw }}</span> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
{% for currency in currencies %}
|
||||
<li><a href="#" class="currencySelect" data-id="{{ currency.id }}" data-field="amount" data-currency="{{ currency.code }}" data-symbol="{{ currency.symbol|raw }}">{{ currency.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{{ Form.input('number', name, value, options) }}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% include 'form/feedback.twig' %}
|
||||
</div>
|
||||
<input type="hidden" name="amount_currency_id" value="{{ defaultCurrency.id }}" />
|
||||
</div>
|
22
resources/twig/form/balance.twig
Normal file
22
resources/twig/form/balance.twig
Normal file
@@ -0,0 +1,22 @@
|
||||
<div class="{{ classes }}">
|
||||
<label for="{{ options.id }}" class="col-sm-4 control-label">{{ label }}</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle balanceCurrencyDropdown" data-toggle="dropdown" aria-expanded="false">
|
||||
<span id="balanceCurrentSymbol">{{ defaultCurrency.symbol|raw }}</span> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
{% for currency in currencies %}
|
||||
<li><a href="#" class="currencySelect" data-id="{{ currency.id }}" data-field="balance" data-currency="{{ currency.code }}" data-symbol="{{ currency.symbol }}">{{ currency.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{{ Form.input('number', name, value, options) }}
|
||||
|
||||
</div>
|
||||
{% include 'form/feedback.twig' %}
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="balance_currency_id" value="{{ defaultCurrency.id }}" />
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user