Newly converted code.

This commit is contained in:
James Cole 2015-02-24 21:10:25 +01:00
parent 49066c282a
commit 5b9c2cdc13
22 changed files with 864 additions and 46 deletions

View File

@ -3,7 +3,14 @@
use FireflyIII\Http\Requests;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Http\Request;
use View;
use Auth;
use Illuminate\Support\Collection;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Account;
use Steam;
/**
* Class PiggyBankController
@ -12,5 +19,52 @@ use Illuminate\Http\Request;
*/
class PiggyBankController extends Controller {
/**
*
*/
public function __construct()
{
View::share('title', 'Piggy banks');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
}
/**
* @return $this
*/
public function index(AccountRepositoryInterface $repository)
{
/** @var Collection $piggyBanks */
$piggyBanks = Auth::user()->piggyBanks()->where('repeats',0)->get();
$accounts = [];
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
$piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100);
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
/*
* Fill account information:
*/
$account = $piggyBank->account;
if (!isset($accounts[$account->id])) {
$accounts[$account->id] = [
'name' => $account->name,
'balance' => Steam::balance($account),
'leftForPiggyBanks' => $repository->leftOnAccount($account),
'sumOfSaved' => $piggyBank->savedSoFar,
'sumOfTargets' => floatval($piggyBank->targetamount),
'leftToSave' => $piggyBank->leftToSave
];
} else {
$accounts[$account->id]['sumOfSaved'] += $piggyBank->savedSoFar;
$accounts[$account->id]['sumOfTargets'] += floatval($piggyBank->targetamount);
$accounts[$account->id]['leftToSave'] += $piggyBank->leftToSave;
}
}
return View::make('piggy-banks.index', compact('piggyBanks', 'accounts'));
}
}

View File

@ -1,8 +1,11 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use ExpandedForm;
use FireflyIII\Http\Requests;
use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Session;
use View;
@ -21,6 +24,39 @@ class TransactionController extends Controller
View::share('mainTitleIcon', 'fa-repeat');
}
/**
* Shows the view helping the user to create a new transaction journal.
*
* @param string $what
*
* @return \Illuminate\View\View
*/
public function create($what = 'deposit')
{
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get()
);
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)';
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = '(no piggy bank)';
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id'];
$subTitle = 'Add a new ' . e($what);
foreach ($respondTo as $r) {
if (!is_null(Input::get($r))) {
$preFilled[$r] = Input::get($r);
}
}
Session::put('preFilled', $preFilled);
asort($piggies);
return view('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle'));
}
/**
* @param $what
*

View File

@ -6,6 +6,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
/*
* Back home.
@ -141,35 +142,35 @@ Breadcrumbs::register(
// piggy banks
Breadcrumbs::register(
'piggyBanks.index', function (Generator $breadcrumbs) {
'piggy-banks.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Piggy banks', route('piggyBanks.index'));
$breadcrumbs->push('Piggy banks', route('piggy-banks.index'));
}
);
Breadcrumbs::register(
'piggyBanks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push('Create new piggy bank', route('piggyBanks.create'));
'piggy-banks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push('Create new piggy bank', route('piggy-banks.create'));
}
);
Breadcrumbs::register(
'piggyBanks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggyBanks.edit', $piggyBank->id));
'piggy-banks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggy-banks.edit', $piggyBank->id));
}
);
Breadcrumbs::register(
'piggyBanks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggyBanks.delete', $piggyBank->id));
'piggy-banks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggy-banks.delete', $piggyBank->id));
}
);
Breadcrumbs::register(
'piggyBanks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggyBanks.show', $piggyBank->id));
'piggy-banks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', $piggyBank->id));
}
);

View File

@ -161,13 +161,13 @@ Route::group(
* Piggy Bank Controller
*/
// piggy bank controller
Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy_banks.index']);
//Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money
//Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money
//Route::get('/piggy-banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy_banks.create']);
//Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy_banks.edit']);
//Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy_banks.delete']);
//Route::get('/piggy-banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy_banks.show']);
Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy-banks.index']);
Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money
Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money
Route::get('/piggy-banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy-banks.create']);
Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']);
Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']);
Route::get('/piggy-banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy-banks.show']);
/**
* Preferences Controller
@ -214,6 +214,12 @@ Route::group(
Route::get('/transaction/edit/{tj}', ['uses' => 'TransactionController@edit', 'as' => 'transactions.edit']);
Route::get('/transaction/delete/{tj}', ['uses' => 'TransactionController@delete', 'as' => 'transactions.delete']);
Route::get('/transaction/show/{tj}', ['uses' => 'TransactionController@show', 'as' => 'transactions.show']);
// transaction controller:
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where(
['what' => 'expenses|revenue|withdrawal|deposit|transfer|transfers']
);
Route::post('/transaction/update/{tj}', ['uses' => 'TransactionController@update', 'as' => 'transactions.update']);
Route::post('/transaction/destroy/{tj}', ['uses' => 'TransactionController@destroy', 'as' => 'transactions.destroy']);
//Route::get('/transaction/relate/{tj}', ['uses' => 'TransactionController@relate', 'as' => 'transactions.relate']);
//Route::post('/transactions/relatedSearch/{tj}', ['uses' => 'TransactionController@relatedSearch', 'as' => 'transactions.relatedSearch']);
//Route::post('/transactions/alreadyRelated/{tj}', ['uses' => 'TransactionController@alreadyRelated', 'as' => 'transactions.alreadyRelated']);

View File

@ -94,4 +94,12 @@ class Account extends Model
return $this->belongsTo('FireflyIII\User');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function piggyBanks()
{
return $this->hasMany('FireflyIII\Models\PiggyBank');
}
}

View File

@ -1,5 +1,7 @@
<?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@ -51,4 +53,59 @@ class PiggyBank extends Model
{
return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable');
}
/**
* Grabs the PiggyBankRepetition that's currently relevant / active
*
* @returns PiggyBankRepetition
*/
public function currentRelevantRep()
{
if ($this->currentRep) {
return $this->currentRep;
}
if ($this->repeats == 0) {
$rep = $this->piggyBankRepetitions()->first(['piggy_bank_repetitions.*']);
$this->currentRep = $rep;
return $rep;
} else {
$query = $this->piggyBankRepetitions()->where(
function (EloquentBuilder $q) {
$q->where(
function (EloquentBuilder $q) {
$q->where(
function (EloquentBuilder $q) {
$today = new Carbon;
$q->whereNull('startdate');
$q->orWhere('startdate', '<=', $today->format('Y-m-d 00:00:00'));
}
)->where(
function (EloquentBuilder $q) {
$today = new Carbon;
$q->whereNull('targetdate');
$q->orWhere('targetdate', '>=', $today->format('Y-m-d 00:00:00'));
}
);
}
)->orWhere(
function (EloquentBuilder $q) {
$today = new Carbon;
$q->where('startdate', '>=', $today->format('Y-m-d 00:00:00'));
$q->where('targetdate', '>=', $today->format('Y-m-d 00:00:00'));
}
);
}
)->orderBy('startdate', 'ASC');
$result = $query->first(['piggy_bank_repetitions.*']);
$this->currentRep = $result;
return $result;
}
}
}

View File

@ -9,6 +9,7 @@ use Config;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
@ -309,4 +310,21 @@ class AccountRepository implements AccountRepositoryInterface
return $journal;
}
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account)
{
$balance = \Steam::balance($account);
/** @var PiggyBank $p */
foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
}
}

View File

@ -49,4 +49,11 @@ interface AccountRepositoryInterface
* @return Account
*/
public function update(Account $account, array $data);
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account);
}

View File

@ -3,6 +3,7 @@
namespace FireflyIII\Support;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
use Input;
use Session;
@ -15,7 +16,6 @@ use View;
*/
class ExpandedForm
{
/**
* @param $name
* @param null $value
@ -23,18 +23,20 @@ class ExpandedForm
*
* @return string
*/
public function balance($name, $value = null, array $options = [])
public function amount($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'] = 'any';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amount::getDefaultCurrency();
$options['min'] = '0.01';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : \Amount::getDefaultCurrency();
$currencies = TransactionCurrency::orderBy('code', 'ASC')->get();
$html = View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
$html = View::make('form.amount', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
@ -124,6 +126,27 @@ class ExpandedForm
return $value;
}
/**
* @param $name
* @param null $value
* @param array $options
*
* @return string
*/
public function balance($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'] = 'any';
$defaultCurrency = isset($options['currency']) ? $options['currency'] : Amount::getDefaultCurrency();
$currencies = TransactionCurrency::orderBy('code', 'ASC')->get();
$html = View::make('form.balance', compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
* @param $name
* @param int $value
@ -165,6 +188,40 @@ class ExpandedForm
return $html;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* Takes any collection and tries to make a sensible select list compatible array of it.
*
* @param Collection $set
* @param bool $addEmpty
*
* @return mixed
*/
public function makeSelectList(Collection $set, $addEmpty = false)
{
$selectList = [];
if ($addEmpty) {
$selectList[0] = '(none)';
}
$fields = ['title', 'name', 'description'];
/** @var \Eloquent $entry */
foreach ($set as $entry) {
$id = intval($entry->id);
$title = null;
foreach ($fields as $field) {
if (isset($entry->$field)) {
$title = $entry->$field;
}
}
$selectList[$id] = $title;
}
return $selectList;
}
/**
* @param $type
* @param $name

View File

@ -72,7 +72,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
*/
public function piggyBanks()
{
return $this->hasManyThrough('FireflyIII\Models\PiggyBank', 'Account');
return $this->hasManyThrough('FireflyIII\Models\PiggyBank', 'FireflyIII\Models\Account');
}
/**

1
public/js/bootstrap3-typeahead.min.js vendored Normal file

File diff suppressed because one or more lines are too long

22
public/js/piggy-banks.js Normal file
View File

@ -0,0 +1,22 @@
$(function () {
$('.addMoney').on('click', addMoney);
$('.removeMoney').on('click', removeMoney);
if (typeof(googleLineChart) === 'function' && typeof(piggyBankID) !== 'undefined') {
googleLineChart('chart/piggy-history/' + piggyBankID, 'piggy-bank-history');
}
});
function addMoney(e) {
var pigID = parseInt($(e.target).data('id'));
$('#moneyManagementModal').empty().load('piggy-banks/add/' + pigID).modal('show');
return false;
}
function removeMoney(e) {
var pigID = parseInt($(e.target).data('id'));
$('#moneyManagementModal').empty().load('piggy-banks/remove/' + pigID).modal('show');
return false;
}

21
public/js/transactions.js Normal file
View File

@ -0,0 +1,21 @@
if ($('input[name="expense_account"]').length > 0) {
$.getJSON('json/expense-accounts').success(function (data) {
$('input[name="expense_account"]').typeahead({source: data});
});
}
if ($('input[name="revenue_account"]').length > 0) {
$.getJSON('json/revenue-accounts').success(function (data) {
$('input[name="revenue_account"]').typeahead({source: data});
});
}
if ($('input[name="category"]').length > 0) {
$.getJSON('json/categories').success(function (data) {
$('input[name="category"]').typeahead({source: data});
});
}
$(document).ready(function () {
if(typeof googleTablePaged != 'undefined') {
googleTablePaged('table/transactions/' + what,'transaction-table');
}
});

View File

@ -137,8 +137,8 @@
</li>
<?php
$isMM = !(strpos($r,'piggy_banks') === false) || !(strpos($r,'bills') === false) | !(strpos($r,'repeated') === false);
$isPiggy = !(strpos($r,'piggy_banks') === false);
$isMM = !(strpos($r,'piggy-banks') === false) || !(strpos($r,'bills') === false) | !(strpos($r,'repeated') === false);
$isPiggy = !(strpos($r,'piggy-banks') === false);
$isBill = !(strpos($r,'bills') === false) && strpos($r,'bills.create') === false;
$isRep = !(strpos($r,'repeated') === false);
?>
@ -146,7 +146,7 @@
<a href="#"><i class="fa fa-euro fa-fw"></i> Money management<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li>
<a @if($isPiggy)class="active"@endif href="{{route('piggy_banks.index')}}"><i class="fa fa-sort-amount-asc fa-fw"></i> Piggy banks</a>
<a @if($isPiggy)class="active"@endif href="{{route('piggy-banks.index')}}"><i class="fa fa-sort-amount-asc fa-fw"></i> Piggy banks</a>
</li>
<li>
<a @if($isBill)class="active"@endif href="{{route('bills.index')}}"><i class="fa fa-calendar-o fa-fw"></i> Bills</a>

View File

@ -0,0 +1,24 @@
<form style="display: inline;" id="add" action="{{route('piggy-banks.add',$piggyBank->id)}}" method="POST">
{{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">Add money to {{{$piggyBank->name}}}</h4>
</div>
<div class="modal-body">
<p>
The maximum amount you can add is {{Amount::format($maxAmount)}}
</p>
<div class="input-group">
<div class="input-group-addon"></div>
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{round($maxAmount,2)}}" type="number">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,94 @@
@extends('layouts.default')
@section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) }}
{{Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('piggy-banks.store')])}}
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
</div>
<div class="panel-body">
{{Form::ffText('name')}}
{{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}}
{{Form::ffAmount('targetamount')}}
</div>
</div>
<p>
<button type="submit" class="btn btn-lg btn-success">
<i class="fa fa-plus-circle"></i> Store new piggy bank
</button>
</p>
</div>
<div class="col-lg-6 col-md-12 col-sm-12">
<!-- 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">
{{Form::ffDate('targetdate')}}
{{Form::ffCheckbox('remind_me','1',false,['label' => 'Remind me'])}}
{{Form::ffSelect('reminder',$periods,'month',['label' => 'Remind every'])}}
</div>
</div>
<!-- panel for options -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bolt"></i> Options
</div>
<div class="panel-body">
{{Form::ffOptionsList('create','piggy bank')}}
</div>
</div>
</div>
</div>
{{--
<h4>Mandatory fields</h4>
<h4>Optional fields</h4>
<div class="form-group">
{{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}}
<div class="col-sm-8">
<input type="number" step="1" min="1" value="{{Input::old('reminder_skip') ?: 1}}" style="width:50px;display:inline;" max="100" name="reminder_skip" class="form-control" />
<select class="form-control" name="reminder" style="width:150px;display: inline">
<option value="none" label="do not remind me">do not remind me</option>
@foreach($periods as $period)
<option value="{{$period}}" label="{{$period}}">{{$period}}</option>
@endforeach
</select>
@if($errors->has('reminder'))
<p class="text-danger">{{$errors->first('reminder')}}</p>
@else
<span class="help-block">Enter a number and a period and Firefly will remind you to add money
to this piggy bank every now and then.</span>
@endif
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<button type="submit" class="btn btn-default btn-success">Create the piggy bank</button>
</div>
</div>
</div>
</div>
--}}
{{Form::close()}}
@stop

View File

@ -0,0 +1,37 @@
@extends('layouts.default')
@section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) }}
{{Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('piggy-banks.destroy',$piggyBank->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 piggy bank "{{{$piggyBank->name}}}"
</div>
<div class="panel-body">
<p>
Are you sure?
</p>
<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>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<div class="col-sm-8">
</div>
</div>
</div>
</div>
{{Form::close()}}
@stop

View File

@ -0,0 +1,94 @@
@extends('layouts.default')
@section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) }}
{{Form::model($piggyBank, ['class' => 'form-horizontal','id' => 'update','url' => route('piggy-banks.update',$piggyBank->id)])}}
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
</div>
<div class="panel-body">
{{Form::ffText('name')}}
{{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}}
{{Form::ffAmount('targetamount')}}
</div>
</div>
<p>
<button type="submit" class="btn btn-lg btn-success">
<i class="fa fa-pencil"></i> Update piggy bank
</button>
</p>
</div>
<div class="col-lg-6 col-md-12 col-sm-12">
<!-- 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">
{{Form::ffDate('targetdate')}}
{{Form::ffCheckbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me'])}}
{{Form::ffSelect('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every'])}}
</div>
</div>
<!-- panel for options -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bolt"></i> Options
</div>
<div class="panel-body">
{{Form::ffOptionsList('update','piggy bank')}}
</div>
</div>
</div>
</div>
{{--
<h4>Mandatory fields</h4>
<h4>Optional fields</h4>
<div class="form-group">
{{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}}
<div class="col-sm-8">
<input type="number" step="1" min="1" value="{{Input::old('reminder_skip') ?: 1}}" style="width:50px;display:inline;" max="100" name="reminder_skip" class="form-control" />
<select class="form-control" name="reminder" style="width:150px;display: inline">
<option value="none" label="do not remind me">do not remind me</option>
@foreach($periods as $period)
<option value="{{$period}}" label="{{$period}}">{{$period}}</option>
@endforeach
</select>
@if($errors->has('reminder'))
<p class="text-danger">{{$errors->first('reminder')}}</p>
@else
<span class="help-block">Enter a number and a period and Firefly will remind you to add money
to this piggy bank every now and then.</span>
@endif
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<button type="submit" class="btn btn-default btn-success">Create the piggy bank</button>
</div>
</div>
</div>
</div>
--}}
{{Form::close()}}
@stop

View File

@ -0,0 +1,132 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p>
<a href="{{route('piggy-banks.create')}}" class="btn btn-success">Create new piggy bank</a>
</p>
</div>
</div>
@foreach($piggyBanks as $piggyBank)
<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 fa-rocket"></i> <a href="{{route('piggy-banks.show',$piggyBank->id)}}" title="{{{$piggyBank->name}}}">{{{$piggyBank->name}}}</a>
<!-- 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('piggy-banks.edit',$piggyBank->id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
<li><a href="{{route('piggy-banks.delete',$piggyBank->id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
</ul>
</div>
</div>
</div>
<div class="panel-body">
<div class="row">
<!-- One block -->
<div class="col-lg-1 col-md-4 col-sm-4 col-xs-4">
<div class="btn-group btn-group-xs">
@if($piggyBank->leftToSave > 0)
<a href="#" class="btn btn-default addMoney" data-id="{{{$piggyBank->id}}}"><span data-id="{{{$piggyBank->id}}}" class="glyphicon glyphicon-plus"></span></a>
@endif
<a href="#" class="btn btn-default removeMoney" data-id="{{{$piggyBank->id}}}"><span data-id="{{{$piggyBank->id}}}" class="glyphicon glyphicon-minus"></span></a>
</div>
</div>
<!-- One block -->
<div class="col-lg-1 col-md-4 col-sm-4 col-xs-4">
<div class="btn-group btn-group-xs">
<a href="{{route('piggy-banks.edit',$piggyBank->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
<a href="{{route('piggy-banks.delete',$piggyBank->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
</div>
</div>
<!-- One block -->
<div class="col-lg-1 col-md-4 col-sm-4 col-xs-4">
{!! Amount::format($piggyBank->savedSoFar,true) !!}
</div>
<!-- One block -->
<div class="col-lg-7 col-md-12 col-sm-12 col-xs-12">
<div class="progress progress-striped">
<div
@if($piggyBank->percentage == 100)
class="progress-bar progress-bar-success"
@else
class="progress-bar progress-bar-info"
@endif
role="progressbar" aria-valuenow="{{$piggyBank->percentage}}" aria-valuemin="0" aria-valuemax="100" style="min-width: 40px;width: {{$piggyBank->percentage}}%;">
{{$piggyBank->percentage}}%
</div>
</div>
</div>
<!-- One block -->
<div class="col-lg-1 col-md-6 col-sm-6 col-xs-6">
{!! Amount::format($piggyBank->targetamount,true) !!}
</div>
<!-- One block -->
<div class="col-lg-1 col-md-6 col-sm-6 col-xs-6">
@if($piggyBank->leftToSave > 0)
{!! Amount::format($piggyBank->leftToSave) !!}
@endif
</div>
</div>
</div>
</div>
</div>
</div>
@endforeach
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p>
<a href="{{route('piggy-banks.create')}}" class="btn btn-success">Create new piggy bank</a>
</p>
</div>
</div>
<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 fa-money"></i> Account status
</div>
<div class="panel-body">
<table class="table table-striped">
<tr>
<th>Account</th>
<th>Balance</th>
<th>Left for piggy banks</th>
<th>Sum of piggy banks</th>
<th>Saved so far</th>
<th>Left to save</th>
</tr>
@foreach($accounts as $id => $info)
<tr>
<td><a href="{{route('accounts.show',$id)}}">{{{$info['name']}}}</a></td>
<td>{!! Amount::format($info['balance']) !!}</td>
<td>{!! Amount::format($info['leftForPiggyBanks']) !!}</td>
<td>{!! Amount::format($info['sumOfTargets']) !!}</td>
<td>{!! Amount::format($info['sumOfSaved']) !!}</td>
<td>{!! Amount::format($info['leftToSave']) !!}</td>
</tr>
@endforeach
</table>
</div>
</div>
</div>
</div>
<!-- this is the modal for the add/remove money routine: -->
<div class="modal fade" id="moneyManagementModal">
</div><!-- /.modal -->
@stop
@section('scripts')
<script type="text/javascript" src="js/piggy-banks.js"></script>
@stop

View File

@ -0,0 +1,24 @@
<form style="display: inline;" id="remove" action="{{route('piggy-banks.remove',$piggyBank->id)}}" method="POST">
{{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">Remove money from {{{$piggyBank->name}}}</h4>
</div>
<div class="modal-body">
<p>
The maximum amount you can remove is {{Amount::format($piggyBank->currentRelevantRep()->currentamount)}}
</p>
<div class="input-group">
<div class="input-group-addon"></div>
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{round($piggyBank->currentRelevantRep()->currentamount,2)}}" type="number">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Remove</button>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,125 @@
@extends('layouts.default')
@section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) }}
<div class="row">
<div class="col-lg-8 col-md-8 col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-clock-o"></i> Events
</div>
<div class="panel-body">
<div id="piggy-bank-history"></div>
</div>
</div>
</div>
<div class="col-lg-4 col-md-4 col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-info-circle"></i> Details
<!-- 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('piggy-banks.edit',$piggyBank->id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
<li><a href="{{route('piggy-banks.delete',$piggyBank->id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
</ul>
</div>
</div>
</div>
<div class="panel-body">
<table class="table table-bordered table-striped">
<tr>
<td>Account</td>
<td><a href="{{route('accounts.show',$piggyBank->account_id)}}">{{{$piggyBank->account->name}}}</a></td>
</tr>
<tr>
<td>Target amount</td>
<td>{{Amount::format($piggyBank->targetamount)}}</td>
</tr>
<tr>
<td>Saved so far</td>
<td>{{Amount::format($piggyBank->currentRelevantRep()->currentamount)}}</td>
</tr>
<tr>
<td>Left to save</td>
<td>{{Amount::format($piggyBank->targetamount-$piggyBank->currentRelevantRep()->currentamount)}}</td>
</tr>
<tr>
<td>Start date</td>
<td>
@if(is_null($piggyBank->startdate))
<em>No start date</em>
@endif
@if(is_object($piggyBank->startdate))
{{$piggyBank->startdate->format('jS F Y')}}
@endif
</td>
</tr>
<tr>
<td>Target date</td>
<td>
@if(is_null($piggyBank->targetdate))
<em>No target date</em>
@endif
@if(is_object($piggyBank->targetdate))
{{$piggyBank->targetdate->format('jS F Y')}}
@endif
</td>
</tr>
@if(!is_null($piggyBank->reminder))
<tr>
<td>Reminder</td>
<td>
@if(intval($piggyBank->remind_me) == 0)
<em>(no reminder)</em>
@else
Every
@if($piggyBank->reminder_skip != 0)
{{$piggyBank->reminder_skip}}
@endif
{{$piggyBank->reminder}}(s)
@endif
</td>
</tr>
@endif
<tr>
<td>Reminders left</td>
<td>(in progress...)</td>
</tr>
<tr>
<td>Expected amount per reminder</td>
<td>(in progress...)</td>
</tr>
</table>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-clock-o"></i> Table
</div>
<div class="panel-body">
@include('list.piggy-bank-events')
</div>
</div>
</div>
</div>
@stop
@section('scripts')
<script type="text/javascript">
var piggyBankID = {{{$piggyBank->id}}};
</script>
<!-- load the libraries and scripts necessary for Google Charts: -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
{{HTML::script('assets/javascript/firefly/gcharts.options.js')}}
{{HTML::script('assets/javascript/firefly/gcharts.js')}}
{{HTML::script('assets/javascript/firefly/piggy-banks.js')}}
@stop

View File

@ -1,8 +1,8 @@
@extends('layouts.default')
@section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) }}
{{Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('transactions.store',$what)])}}
{{Form::hidden('reminder',Input::get('reminder_id'))}}
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) !!}
{!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('transactions.store',$what)]) !!}
{!! Form::hidden('reminder',Input::get('reminder_id')) !!}
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-12">
@ -13,35 +13,35 @@
</div>
<div class="panel-body">
<!-- DESCRIPTION ALWAYS AVAILABLE -->
{{Form::ffText('description')}}
{!! ExpandedForm::text('description') !!}
@if($what == 'deposit' || $what == 'withdrawal')
{{Form::ffSelect('account_id',$accounts)}}
{!! ExpandedForm::select('account_id',$accounts) !!}
@endif
<!-- SHOW EXPENSE ACCOUNT ONLY FOR WITHDRAWALS -->
@if($what == 'withdrawal')
{{Form::ffText('expense_account')}}
{{ExpandedForm::text('expense_account')}}
@endif
<!-- SHOW REVENUE ACCOUNT ONLY FOR DEPOSITS -->
@if($what == 'deposit')
{{Form::ffText('revenue_account')}}
{{ExpandedForm::text('revenue_account')}}
@endif
<!-- ONLY SHOW FROM/TO ACCOUNT WHEN CREATING TRANSFER -->
@if($what == 'transfer')
{{Form::ffSelect('account_from_id',$accounts)}}
{{Form::ffSelect('account_to_id',$accounts)}}
{{ExpandedForm::select('account_from_id',$accounts)}}
{{ExpandedForm::select('account_to_id',$accounts)}}
@endif
<!-- ALWAYS SHOW AMOUNT -->
{{Form::ffAmount('amount')}}
{{ExpandedForm::amount('amount')}}
<!-- ALWAYS SHOW DATE -->
{{Form::ffDate('date', date('Y-m-d'))}}
{{ExpandedForm::date('date', date('Y-m-d'))}}
</div>
</div>
<p>
@ -60,17 +60,17 @@
<div class="panel-body">
<!-- BUDGET ONLY WHEN CREATING A WITHDRAWAL -->
@if($what == 'withdrawal')
{{Form::ffSelect('budget_id',$budgets,0)}}
{{ExpandedForm::select('budget_id',$budgets,0)}}
@endif
<!-- CATEGORY ALWAYS -->
{{Form::ffText('category')}}
{{ExpandedForm::text('category')}}
<!-- TAGS -->
<!-- RELATE THIS TRANSFER TO A PIGGY BANK -->
@if($what == 'transfer' && count($piggies) > 0)
{{Form::ffSelect('piggy_bank_id',$piggies)}}
{{ExpandedForm::select('piggy_bank_id',$piggies)}}
@endif
</div>
</div>
@ -80,7 +80,7 @@
<i class="fa fa-bolt"></i> Options
</div>
<div class="panel-body">
{{Form::ffOptionsList('create','transaction')}}
{{ExpandedForm::optionsList('create','transaction')}}
</div>
</div>
</div>
@ -91,6 +91,6 @@
@stop
@section('scripts')
{{HTML::script('assets/javascript/typeahead/bootstrap3-typeahead.min.js')}}
{{HTML::script('assets/javascript/firefly/transactions.js')}}
<script type="text/javascript" src="js/bootstrap3-typeahead.min.js"></script>
<script type="text/javascript" src="js/transactions.js"></script>
@stop