Compare commits

...

89 Commits
3.3.8 ... 3.4

Author SHA1 Message Date
James Cole
ae90815708 Merge branch 'release/3.4' 2015-05-02 23:51:44 +02:00
James Cole
1c460343b7 New version! 2015-05-02 23:51:34 +02:00
James Cole
26079622f9 Fixed JSON controller tests. 2015-05-02 23:39:39 +02:00
James Cole
06c6d6096f Fixed coverage. 2015-05-02 23:28:04 +02:00
James Cole
c8183aea51 Format amount [skip ci] 2015-05-02 22:50:40 +02:00
James Cole
7531134ad2 Some tag related fine tuning. 2015-05-02 22:41:32 +02:00
James Cole
cd0c6439c2 Delete tags now possible. 2015-05-02 22:30:59 +02:00
James Cole
c918c93f51 Forget me own head next. [skip ci] 2015-05-02 22:13:37 +02:00
James Cole
97d3bd68ed Show balance act tags. 2015-05-02 22:12:26 +02:00
James Cole
75f1e034ae Fixed menu. [skip ci] 2015-05-02 22:09:21 +02:00
James Cole
8e72f218f1 Show HTML 2015-05-02 22:05:57 +02:00
James Cole
d643e05c5a Basic amount format fix. 2015-05-02 22:05:18 +02:00
James Cole
fea44834d0 Fixed test to match fixed controller. 2015-05-02 21:22:27 +02:00
James Cole
195a2d7523 Removed all the old views. 2015-05-02 21:18:04 +02:00
James Cole
b2fd346ef8 Merge branch 'feature/twig' into develop 2015-05-02 21:16:21 +02:00
James Cole
1ff8b62cb7 And now with actual coverage. 2015-05-02 19:44:31 +02:00
James Cole
c7ae15a41a This should fix all twig tests. Let's find out! 2015-05-02 19:44:12 +02:00
James Cole
efe6f59f79 Last templates. Should cover everything. [skip ci] 2015-05-02 19:19:47 +02:00
James Cole
8e31d0491d Fixed search [skip ci] 2015-05-02 18:30:59 +02:00
James Cole
73d4a10351 Fixed reports [skip ci] 2015-05-02 18:26:55 +02:00
James Cole
81d9d4dbc7 Various files updated to twig [skip ci] 2015-05-02 13:20:49 +02:00
James Cole
184ec13f99 Fixed bills [skip ci] 2015-05-02 12:51:02 +02:00
James Cole
dee0422eff Fix preferences [skip ci] 2015-05-02 12:22:19 +02:00
James Cole
81a2975f1a Show piggy banks [skip ci] 2015-05-02 11:32:45 +02:00
James Cole
5cd2ef4a5e Some generic templates and the first piggy bank ones [skip ci] 2015-05-02 10:53:54 +02:00
James Cole
466c2a68c2 Add delete form [skip ci] 2015-05-02 10:42:41 +02:00
James Cole
0fb9fba531 New currency routes 2015-05-02 10:40:20 +02:00
James Cole
356dd2c6cd Creat / edit / index [skip ci] 2015-05-02 10:37:16 +02:00
James Cole
32c4661233 Fixed no budget / no category bread crumb [skip ci] 2015-05-02 09:49:37 +02:00
James Cole
a245b504ec Fixed bread crumbs. 2015-05-02 09:31:57 +02:00
James Cole
a2f5fbdfd3 Working on two more views [skip ci] 2015-05-02 09:29:34 +02:00
James Cole
04be26adc5 Fixed title [skip ci] 2015-05-02 09:26:20 +02:00
James Cole
be0adb7cf2 Create / edit category 2015-05-02 09:25:45 +02:00
James Cole
84fd92bf5a Categories [skip ci] 2015-05-02 09:21:42 +02:00
James Cole
ee4e061739 Removed code from budget index [skip ci] 2015-05-02 09:21:32 +02:00
James Cole
4a2b01cd9a Menu fixes [skip ci] 2015-05-02 09:16:17 +02:00
James Cole
efdd6460fb Fixed injection. 2015-05-02 09:08:41 +02:00
James Cole
803827e05c Fixed more views. [skip ci] 2015-05-02 09:06:07 +02:00
James Cole
a41d5e9ab3 New budget [skip ci] 2015-05-02 08:32:20 +02:00
James Cole
e94333f877 Can view budgets [skip ci] 2015-05-02 08:28:24 +02:00
James Cole
6dbb80d687 Optimisations [skip ci] 2015-05-02 08:09:54 +02:00
James Cole
31a1031624 And delete is fixed. 2015-05-01 23:39:45 +02:00
James Cole
f8e9ce0d52 Can edit as well. 2015-05-01 23:35:35 +02:00
James Cole
11baa968cd Can create accounts. 2015-05-01 23:17:17 +02:00
James Cole
3e5e5b376f Made it almost to the accounts. 2015-05-01 22:44:35 +02:00
James Cole
bda18f296d Optimised Twig extensions. 2015-05-01 20:17:06 +02:00
James Cole
287d110c84 Small bug fix in budget chart. 2015-05-01 18:45:42 +02:00
James Cole
c98275e73a More templates converted to twig. 2015-05-01 18:44:49 +02:00
James Cole
aa573cc951 Fix redirect 2015-05-01 14:32:31 +02:00
James Cole
883d3d86e3 Update a test. 2015-05-01 14:32:26 +02:00
James Cole
fb047bd5f4 Fix migration. 2015-05-01 08:34:53 +02:00
James Cole
66a04d8365 Slightly different chart on index. 2015-05-01 08:34:44 +02:00
James Cole
a0e501f9fd First attempt at implementing Twig. 2015-05-01 08:29:41 +02:00
James Cole
8b40d3346d An attempt at showing tag info. 2015-05-01 06:47:24 +02:00
James Cole
eddf5cd250 Fix button, close #74 2015-05-01 06:38:48 +02:00
James Cole
ee5c534ca3 Took the time to fix the tests. 2015-04-30 17:32:00 +02:00
James Cole
fd4e77ae0f Catch empty tags. 2015-04-28 21:01:54 +02:00
James Cole
b747c50aa3 Fix method to return object, not key. 2015-04-28 21:00:26 +02:00
James Cole
deebdd86a6 And another small JS fix [skip ci] 2015-04-28 20:20:16 +02:00
James Cole
b2db79cc10 Fixed some small CSS / JS problems. 2015-04-28 20:17:31 +02:00
James Cole
bbab370b1e Some new code. 2015-04-28 17:10:52 +02:00
James Cole
db4adf399d Cleaning up. 2015-04-28 15:26:30 +02:00
James Cole
0683c87e52 Small check in tags. 2015-04-28 14:08:58 +02:00
James Cole
3f62b647fc Removed code related to "related transactions". 2015-04-28 13:50:53 +02:00
James Cole
2562a5b30d Don't save all tags unconditionally. 2015-04-28 13:47:13 +02:00
James Cole
e232f2e223 Delete tags 2015-04-28 11:04:46 +02:00
James Cole
21644ff4dd Routes will throw 404's 2015-04-28 11:04:38 +02:00
James Cole
be96a4fce5 Show tags in transaction. 2015-04-28 10:51:56 +02:00
James Cole
a1cabcbed3 Show tag icons. 2015-04-28 10:50:43 +02:00
James Cole
ce933b1f06 Edit and update tags. 2015-04-28 10:36:13 +02:00
James Cole
51ae130922 Fixed the build by adding new migrations for each step. 2015-04-28 09:54:22 +02:00
James Cole
da1bc18a47 Better list for piggy banks. 2015-04-28 09:15:31 +02:00
James Cole
e7165a526b First attempt at basic tag functionality. 2015-04-28 08:58:01 +02:00
James Cole
6081cc399f Small bug fixes and cleaning up. 2015-04-28 08:12:12 +02:00
James Cole
7c5c24e15d Moved edit buttons. 2015-04-26 07:42:55 +02:00
James Cole
e3e55b4347 Moved all create-buttons lower. 2015-04-26 07:39:49 +02:00
James Cole
40d8e7d1ad Fixed a bug where transfers away from a piggy bank's account would not properly reflect the piggy bank. 2015-04-24 12:06:13 +02:00
James Cole
59e23b89f2 Removed unnecessary sort. 2015-04-24 11:54:23 +02:00
James Cole
cc33af8193 Could not set order. 2015-04-24 10:00:56 +02:00
James Cole
0e1e7eb2a9 Merge branch 'release/3.3.9' 2015-04-22 08:08:14 +02:00
James Cole
52a28a7758 Merge branch 'release/3.3.9' into develop 2015-04-22 08:08:14 +02:00
James Cole
3f752d6832 New read me. 2015-04-22 08:08:05 +02:00
James Cole
fe714e9989 Built a routine that will allow you to completely delete an account. 2015-04-22 07:54:56 +02:00
James Cole
0d3213a379 Covered the preferences controller. 2015-04-21 17:19:14 +02:00
James Cole
44056629e8 Use local db instead of constant migrating. 2015-04-20 22:08:24 +02:00
James Cole
54125c05d3 New tests and prep for future runs. 2015-04-20 21:57:20 +02:00
James Cole
7d32e50f25 Mentioned wrong amount. 2015-04-20 20:56:28 +02:00
James Cole
4af9ff49a0 Fixed a bug in the report controller that grouped transactions wrong. 2015-04-20 20:54:55 +02:00
James Cole
41dad4091a Merge branch 'release/3.3.8' into develop 2015-04-20 18:07:02 +02:00
218 changed files with 6831 additions and 4176 deletions

18
.env.backup Executable file
View 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
View 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
View File

@@ -28,3 +28,4 @@ tests/_output/*
clover.xml
node_modules/
addNewLines.php
.phpstorm.meta.php

View File

@@ -1,4 +1,4 @@
Firefly III (v3.3.8)
Firefly III (v3.4)
===========
[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii)
@@ -22,7 +22,9 @@ laptop and [Firefly II](https://github.com/JC5/Firefly) is live.
If you're not sure if this tool is for you, please read the [full description](https://github.com/JC5/firefly-iii/wiki/full-description).
To install and use Firefly III, please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation),
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable) and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/). This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site.
## Current features

View File

@@ -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();

View File

@@ -230,7 +230,7 @@ class ReportQuery implements ReportQueryInterface
// any deposit is fine.
$query->where('transaction_types.type', 'Deposit');
}
$query->groupBy('t_from.account_id')->orderBy('transaction_journals.date');
$query->groupBy('transaction_journals.id')->orderBy('transaction_journals.date');
// get everything, decrypt and return
$data = $query->get(

View File

@@ -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'));
}

View File

@@ -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.
*

View File

@@ -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'));
}

View File

@@ -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'));
}
/**

View File

@@ -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());

View File

@@ -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);
}
}

View File

@@ -27,7 +27,7 @@ class CurrencyController extends Controller
*/
public function __construct()
{
parent::__construct();
View::share('title', 'Currencies');
View::share('mainTitleIcon', 'fa-usd');
}

View File

@@ -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');

View File

@@ -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

View File

@@ -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'));
}

View File

@@ -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
*/

View File

@@ -1,12 +1,12 @@
<?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use Carbon\Carbon;
use Config;
use ExpandedForm;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -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');
}
@@ -56,13 +57,13 @@ class PiggyBankController extends Controller
/**
* @return mixed
*/
public function create()
public function create(AccountRepositoryInterface $repository)
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
//Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
// );
$subTitle = 'Create new piggy bank';
$subTitleIcon = 'fa-plus';
@@ -95,11 +96,12 @@ class PiggyBankController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(PiggyBank $piggyBank)
public function destroy(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
{
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
$piggyBank->delete();
$repository->destroy($piggyBank);
return Redirect::to(Session::get('piggy-banks.delete.url'));
}
@@ -111,13 +113,11 @@ class PiggyBankController extends Controller
*
* @return $this
*/
public function edit(PiggyBank $piggyBank)
public function edit(PiggyBank $piggyBank, AccountRepositoryInterface $repository)
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
$subTitleIcon = 'fa-pencil';
@@ -151,16 +151,16 @@ class PiggyBankController extends Controller
/**
* @return $this
*/
public function index(AccountRepositoryInterface $repository)
public function index(AccountRepositoryInterface $repository, PiggyBankRepositoryInterface $piggyRepository)
{
/** @var Collection $piggyBanks */
$piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
$piggyBanks = $piggyRepository->getPiggyBanks();
$accounts = [];
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
$piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100);
$piggyBank->percentage = $piggyBank->savedSoFar != 0 ? intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100) : 0;
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
/*
@@ -223,8 +223,8 @@ class PiggyBankController extends Controller
$repetition->currentamount += $amount;
$repetition->save();
// create event.
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
// create event
$repository->createEvent($piggyBank, $amount);
/*
* Create event!
@@ -244,7 +244,7 @@ class PiggyBankController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postRemove(PiggyBank $piggyBank)
public function postRemove(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
{
$amount = floatval(Input::get('amount'));
@@ -255,12 +255,8 @@ class PiggyBankController extends Controller
$repetition->currentamount -= $amount;
$repetition->save();
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount * -1, 'piggy_bank_id' => $piggyBank->id]);
/*
* Create event!
*/
//Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used.
// create event
$repository->createEvent($piggyBank, $amount * -1);
Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
} else {
@@ -287,10 +283,9 @@ class PiggyBankController extends Controller
*
* @return $this
*/
public function show(PiggyBank $piggyBank)
public function show(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository)
{
$events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
$events = $repository->getEvents($piggyBank);
/*
* Number of reminders:
@@ -310,6 +305,7 @@ class PiggyBankController extends Controller
*/
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
{
$piggyBankData = [
'name' => $request->get('name'),
'startdate' => new Carbon,
@@ -354,7 +350,6 @@ class PiggyBankController extends Controller
'remind_me' => $request->get('remind_me')
];
$piggyBank = $repository->update($piggyBank, $piggyBankData);
Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".');

View File

@@ -1,6 +1,6 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input;
use Preferences;
use Redirect;
@@ -20,7 +20,7 @@ class PreferencesController extends Controller
*/
public function __construct()
{
parent::__construct();
View::share('title', 'Preferences');
View::share('mainTitleIcon', 'fa-gear');
}
@@ -28,9 +28,9 @@ class PreferencesController extends Controller
/**
* @return $this|\Illuminate\View\View
*/
public function index()
public function index(AccountRepositoryInterface $repository)
{
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
$viewRange = Preferences::get('viewRange', '1M');
$viewRangeValue = $viewRange->data;
$frontPage = Preferences::get('frontPageAccounts', []);

View File

@@ -2,6 +2,7 @@
use Auth;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
use FireflyIII\Http\Requests\ProfileFormRequest;
use Hash;
use Redirect;
@@ -34,6 +35,37 @@ class ProfileController extends Controller
return view('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
}
/**
* @return \Illuminate\View\View
*/
public function deleteAccount()
{
return view('profile.delete-account')->with('title', Auth::user()->email)->with('subTitle', 'Delete account')->with(
'mainTitleIcon', 'fa-user'
);
}
/**
*
*/
public function postDeleteAccount(DeleteAccountFormRequest $request)
{
// old, new1, new2
if (!Hash::check($request->get('password'), Auth::user()->password)) {
Session::flash('error', 'Invalid password!');
return Redirect::route('delete-account');
}
// DELETE!
Auth::user()->delete();
Session::flush();
return Redirect::route('index');
}
/**
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/

View File

@@ -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'));
}
}

View File

@@ -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'));
}

View 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'));
}
}

View File

@@ -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);

View File

@@ -0,0 +1,32 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
/**
* Class DeleteAccountFormRequest
*
* @package FireflyIII\Http\Requests
*/
class DeleteAccountFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
return [
'password' => 'required',
];
}
}

View File

@@ -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')),
];
}

View 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'
];
}
}

View File

@@ -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));
}
);

View File

@@ -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']);
@@ -282,18 +312,10 @@ Route::group(
*/
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
Route::get('/profile/delete-account', ['uses' => 'ProfileController@deleteAccount', 'as' => 'delete-account']);
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
*/
@@ -325,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
*/

View File

@@ -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
View 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');
}
}

View File

@@ -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
*/

View File

@@ -35,6 +35,7 @@ class AppServiceProvider extends ServiceProvider
'Illuminate\Contracts\Auth\Registrar',
'FireflyIII\Services\Registrar'
);
}
}

View File

@@ -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' => [],
],
]
]
);
}

View File

@@ -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');
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -3,8 +3,10 @@
namespace FireflyIII\Repositories\PiggyBank;
use Auth;
use Carbon\Carbon;
use DB;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\PiggyBankRepetition;
use Illuminate\Support\Collection;
use Navigation;
@@ -69,6 +71,19 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $bars;
}
/**
* @param PiggyBank $piggyBank
* @param $amount
*
* @return bool
*/
public function createEvent(PiggyBank $piggyBank, $amount)
{
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
return true;
}
/**
* @param array $data
*
@@ -87,6 +102,16 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $part;
}
/**
* @param PiggyBank $piggyBank
*
* @return bool
*/
public function destroy(PiggyBank $piggyBank)
{
return $piggyBank->delete();
}
/**
* @param PiggyBank $piggyBank
*
@@ -97,7 +122,26 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
}
/**
* @param PiggyBank $piggyBank
*
* @return Collection
*/
public function getEvents(PiggyBank $piggyBank)
{
return $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
}
/**
* @return Collection
*/
public function getPiggyBanks()
{
/** @var Collection $set */
$set = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
return $set;
}
/**
* Set all piggy banks to order 0.

View File

@@ -27,6 +27,18 @@ interface PiggyBankRepositoryInterface
*/
public function calculateParts(PiggyBankRepetition $repetition);
/**
* @return Collection
*/
public function getPiggyBanks();
/**
* @param PiggyBank $piggyBank
*
* @return Collection
*/
public function getEvents(PiggyBank $piggyBank);
/**
* @param array $data
*
@@ -34,6 +46,14 @@ interface PiggyBankRepositoryInterface
*/
public function createPiggyBankPart(array $data);
/**
* @param PiggyBank $piggyBank
* @param $amount
*
* @return bool
*/
public function createEvent(PiggyBank $piggyBank, $amount);
/**
* @param PiggyBank $piggyBank
*
@@ -41,6 +61,13 @@ interface PiggyBankRepositoryInterface
*/
public function getEventSummarySet(PiggyBank $piggyBank);
/**
* @param PiggyBank $piggyBank
*
* @return bool
*/
public function destroy(PiggyBank $piggyBank);
/**
* Set all piggy banks to order 0.
*

View 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;
}
}

View 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);
}

View File

@@ -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()

View File

@@ -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;
}
}

View 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';
}
}

View 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';
}
}

View 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';
}
}

View 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';
}
}

View File

@@ -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
*/

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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",

327
composer.lock generated
View File

@@ -4,24 +4,24 @@
"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",
"version": "1.2.0",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/ClassPreloader/ClassPreloader.git",
"reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f"
"reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/f0bfbf71fb3335c9473f695d4d966ba2fb879a9f",
"reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f",
"url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/0544616ba33fb2a6b792b3a7822650810c6d65d9",
"reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9",
"shasum": ""
},
"require": {
"nikic/php-parser": "~1.0",
"nikic/php-parser": "^1.2.2",
"php": ">=5.3.3",
"symfony/console": "~2.1",
"symfony/filesystem": "~2.1",
@@ -36,7 +36,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
@@ -64,7 +64,7 @@
"class",
"preload"
],
"time": "2015-01-26 22:06:19"
"time": "2015-04-15 21:59:30"
},
{
"name": "danielstjules/stringy",
@@ -206,16 +206,16 @@
},
{
"name": "doctrine/annotations",
"version": "v1.2.3",
"version": "v1.2.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4"
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4",
"reference": "eeda578cbe24a170331a1cfdf78be723412df7a4",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b5202eb9e83f8db52e0e58867e0a46e63be8332e",
"reference": "b5202eb9e83f8db52e0e58867e0a46e63be8332e",
"shasum": ""
},
"require": {
@@ -270,20 +270,20 @@
"docblock",
"parser"
],
"time": "2014-12-20 20:49:38"
"time": "2014-12-23 22:40:37"
},
{
"name": "doctrine/cache",
"version": "v1.4.0",
"version": "v1.4.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
"reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
"url": "https://api.github.com/repos/doctrine/cache/zipball/c9eadeb743ac6199f7eec423cb9426bc518b7b03",
"reference": "c9eadeb743ac6199f7eec423cb9426bc518b7b03",
"shasum": ""
},
"require": {
@@ -294,13 +294,13 @@
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"predis/predis": "~0.8",
"predis/predis": "~1.0",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
"dev-master": "1.5.x-dev"
}
},
"autoload": {
@@ -340,25 +340,28 @@
"cache",
"caching"
],
"time": "2015-01-15 20:38:55"
"time": "2015-04-15 00:11:59"
},
{
"name": "doctrine/collections",
"version": "v1.2",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
"url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
@@ -375,17 +378,6 @@
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/",
"role": "Creator"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
@@ -394,11 +386,17 @@
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
"email": "schmittjoh@gmail.com"
}
],
"description": "Collections Abstraction library",
@@ -408,7 +406,7 @@
"collections",
"iterator"
],
"time": "2014-02-03 23:07:43"
"time": "2015-04-14 22:21:58"
},
{
"name": "doctrine/common",
@@ -945,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": {
@@ -1024,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).",
@@ -1067,7 +1065,7 @@
"framework",
"laravel"
],
"time": "2015-04-04 01:34:57"
"time": "2015-04-21 01:44:32"
},
{
"name": "league/commonmark",
@@ -1529,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",
@@ -2293,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",
@@ -3027,23 +3198,23 @@
},
{
"name": "phpspec/phpspec",
"version": "2.1.1",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/phpspec.git",
"reference": "66a1df93099282b1514e9e001fcf6e9393f7783d"
"reference": "9727d75919a00455433e867565bc022f0b985a39"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/phpspec/zipball/66a1df93099282b1514e9e001fcf6e9393f7783d",
"reference": "66a1df93099282b1514e9e001fcf6e9393f7783d",
"url": "https://api.github.com/repos/phpspec/phpspec/zipball/9727d75919a00455433e867565bc022f0b985a39",
"reference": "9727d75919a00455433e867565bc022f0b985a39",
"shasum": ""
},
"require": {
"doctrine/instantiator": "~1.0,>=1.0.1",
"doctrine/instantiator": "^1.0.1",
"php": ">=5.3.3",
"phpspec/php-diff": "~1.0.0",
"phpspec/prophecy": "~1.1",
"phpspec/prophecy": "~1.4",
"sebastian/exporter": "~1.0",
"symfony/console": "~2.3",
"symfony/event-dispatcher": "~2.1",
@@ -3052,9 +3223,11 @@
"symfony/yaml": "~2.1"
},
"require-dev": {
"behat/behat": "~3.0,>=3.0.11",
"behat/behat": "^3.0.11",
"bossa/phpspec2-expect": "~1.0",
"symfony/filesystem": "~2.1"
"phpunit/phpunit": "~4.4",
"symfony/filesystem": "~2.1",
"symfony/process": "~2.1"
},
"suggest": {
"phpspec/nyan-formatters": "~1.0 Adds Nyan formatters"
@@ -3065,7 +3238,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1.x-dev"
"dev-master": "2.2.x-dev"
}
},
"autoload": {
@@ -3099,20 +3272,20 @@
"testing",
"tests"
],
"time": "2015-01-09 13:21:45"
"time": "2015-04-18 16:22:51"
},
{
"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,20 +3332,20 @@
"spy",
"stub"
],
"time": "2015-03-27 19:31:25"
"time": "2015-04-27 22:15:08"
},
{
"name": "phpunit/php-code-coverage",
"version": "2.0.15",
"version": "2.0.16",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "34cc484af1ca149188d0d9e91412191e398e0b67"
"reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67",
"reference": "34cc484af1ca149188d0d9e91412191e398e0b67",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/934fd03eb6840508231a7f73eb8940cf32c3b66c",
"reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c",
"shasum": ""
},
"require": {
@@ -3221,7 +3394,7 @@
"testing",
"xunit"
],
"time": "2015-01-24 10:06:35"
"time": "2015-04-11 04:35:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -3360,16 +3533,16 @@
},
{
"name": "phpunit/php-token-stream",
"version": "1.4.0",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74"
"reference": "eab81d02569310739373308137284e0158424330"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74",
"reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330",
"reference": "eab81d02569310739373308137284e0158424330",
"shasum": ""
},
"require": {
@@ -3405,20 +3578,20 @@
"keywords": [
"tokenizer"
],
"time": "2015-01-17 09:51:32"
"time": "2015-04-08 04:46:07"
},
{
"name": "phpunit/phpunit",
"version": "4.6.1",
"version": "4.6.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "08b2aacdd8433abbba468f995d6d64b76a7a62ec"
"reference": "163232991e652e6efed2f8470326fffa61e848e2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/08b2aacdd8433abbba468f995d6d64b76a7a62ec",
"reference": "08b2aacdd8433abbba468f995d6d64b76a7a62ec",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/163232991e652e6efed2f8470326fffa61e848e2",
"reference": "163232991e652e6efed2f8470326fffa61e848e2",
"shasum": ""
},
"require": {
@@ -3457,9 +3630,6 @@
"autoload": {
"classmap": [
"src/"
],
"files": [
"src/Framework/Assert/Functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -3480,7 +3650,7 @@
"testing",
"xunit"
],
"time": "2015-04-03 13:46:59"
"time": "2015-04-11 05:23:21"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -4182,6 +4352,7 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"rcrowe/twigbridge": 20,
"barryvdh/laravel-debugbar": 0
},
"prefer-stable": false,

View File

@@ -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',
],

View File

@@ -48,7 +48,7 @@ return [
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'database' => __DIR__.'/../storage/database/testing.db',
'prefix' => '',
],

View File

@@ -14,7 +14,7 @@ return [
*/
'paths' => [
realpath(base_path('resources/views'))
realpath(base_path('resources/twig'))
],
/*

View File

@@ -41,6 +41,9 @@ class CreateAccountMetaTable extends Migration
$table->unique(['account_id', 'name']);
// link to account!
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
}
);

View 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');
});
}
}

View 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"
}
}

View 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()
{
//
}
}

View File

@@ -7,7 +7,7 @@
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
stopOnFailure="true"
syntaxCheck="false">
<testsuites>
<testsuite name="Application Test Suite">

5
pu.sh
View File

@@ -1,8 +1,5 @@
#!/bin/bash
# backup .env file.
cp .env .env.backup
# set testing environment
cp .env.testing .env
@@ -18,4 +15,4 @@ then
fi
# restore .env file
mv .env.backup .env
cp .env.local .env

View File

@@ -5,4 +5,9 @@
.ui-sortable-placeholder {
display: inline-block;
height: 1px;
}
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}

View 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"}

View File

@@ -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();

View File

@@ -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 + '">&nbsp;</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);

View File

@@ -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.');
});
}

View File

@@ -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
View 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);

View File

@@ -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});

View 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 %}

View 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 %}

View 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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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">&times;</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 %}

View File

@@ -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 &mdash; 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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View 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 %}

View File

@@ -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 %}

View 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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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">&times;</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">

View 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 %}

View File

@@ -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 %}

View 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 %}

View File

@@ -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

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View 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 %}

View File

@@ -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>&nbsp;</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 %}

View File

@@ -0,0 +1 @@
Click here to reset your password: {{ url('password/reset/' . token) }}

Some files were not shown because too many files have changed in this diff Show More