Moved to high charts.

This commit is contained in:
James Cole
2014-07-15 06:58:08 +02:00
parent 6e7ea89c70
commit 0e09e52e45
26 changed files with 2055 additions and 85 deletions

View File

@@ -49,7 +49,7 @@ class AccountController extends \BaseController
}
}
return View::make('accounts.index')->with('accounts', $list)->with('total',$total);
return View::make('accounts.index')->with('accounts', $list)->with('total', $total);
}
//
//
@@ -128,4 +128,6 @@ class AccountController extends \BaseController
// }
}

View File

@@ -23,45 +23,39 @@ class ChartController extends BaseController
{
list($start, $end) = tk::getDateRange();
$current = clone $start;
// chart
$chart = App::make('gchart');
$chart->addColumn('Day of the month', 'date');
$return = [];
if (is_null($account)) {
// get accounts:
$accounts = $this->accounts->getActiveDefault();
foreach ($accounts as $account) {
$chart->addColumn($account->name, 'number');
foreach ($accounts as $index => $account) {
$return[] = ['name' => $account->name, 'data' => []];
}
while ($current <= $end) {
$row = [clone $current];
// loop accounts:
foreach ($accounts as $account) {
$row[] = $account->balance(clone $current);
foreach ($accounts as $index => $account) {
$return[$index]['data'][] = [$current->timestamp * 1000, $account->balance(clone $current)];
}
$current->addDay();
$chart->addRowArray($row);
}
} else {
// do something experimental:
$account = $this->accounts->find($account);
if (is_null($account)) {
return View::make('error')->with('message', 'No account found.');
}
$chart->addColumn($account->name, 'number');
while ($current <= $end) {
$row = [clone $current, $account->balance(clone $current)];
$current->addDay();
$chart->addRowArray($row);
}
}
$return[0] = ['name' => $account->name, 'data' => []];
$chart->generate();
return $chart->getData();
while ($current <= $end) {
$return[0]['data'][] = [$current->timestamp * 1000, $account->balance(clone $current)];
$current->addDay();
}
}
return Response::json($return);
}
/**
@@ -70,18 +64,18 @@ class ChartController extends BaseController
public function homeBudgets()
{
list($start, $end) = tk::getDateRange();
$data = [
'type' => 'pie',
'name' => 'Expense: ',
'data' => []
];
$result = $this->journals->homeBudgetChart($start, $end);
// create a chart:
$chart = App::make('gchart');
$chart->addColumn('Budget', 'string');
$chart->addColumn('Amount', 'number');
foreach ($result as $name => $amount) {
$chart->addRow($name, $amount);
$data['data'][] = [$name, $amount];
}
$chart->generate();
return Response::json($chart->getData());
return Response::json([$data]);
}
@@ -93,16 +87,16 @@ class ChartController extends BaseController
list($start, $end) = tk::getDateRange();
$result = $this->journals->homeCategoryChart($start, $end);
$data = [
'type' => 'pie',
'name' => 'Amount: ',
'data' => []
];
// create a chart:
$chart = App::make('gchart');
$chart->addColumn('Category', 'string');
$chart->addColumn('Amount', 'number');
foreach ($result as $name => $amount) {
$chart->addRow($name, $amount);
$data['data'][] = [$name, $amount];
}
$chart->generate();
return Response::json($chart->getData());
return Response::json([$data]);
}
@@ -112,18 +106,18 @@ class ChartController extends BaseController
public function homeBeneficiaries()
{
list($start, $end) = tk::getDateRange();
$data = [
'type' => 'pie',
'name' => 'Amount: ',
'data' => []
];
$result = $this->journals->homeBeneficiaryChart($start, $end);
// create a chart:
$chart = App::make('gchart');
$chart->addColumn('Beneficiary', 'string');
$chart->addColumn('Amount', 'number');
foreach ($result as $name => $amount) {
$chart->addRow($name, $amount);
$data['data'][] = [$name, $amount];
}
$chart->generate();
return Response::json($chart->getData());
return Response::json([$data]);
}
}

View File

@@ -0,0 +1,7 @@
<?php
class ComponentsController extends BaseController {
}

View File

@@ -20,10 +20,6 @@ class HomeController extends BaseController
public function index()
{
// get preferred viewing range
$viewRange = $this->preferences->get('viewRange','week');
// get list setting:
$pref = $this->preferences->get('frontpageAccounts', []);

View File

@@ -0,0 +1,40 @@
<?php
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
use Firefly\Storage\Component\ComponentRepositoryInterface as CRI;
class JsonController extends BaseController
{
public function __construct(ARI $accounts,CRI $components)
{
$this->components = $components;
$this->accounts = $accounts;
}
/**
* Returns a JSON list of all beneficiaries.
*/
public function beneficiaries()
{
$list = $this->accounts->getBeneficiaries();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
* Responds some JSON for typeahead fields.
*/
public function categories()
{
$list = $this->components->get();
}
}

View File

@@ -20,18 +20,31 @@ class PreferencesController extends BaseController
{
$accounts = $this->accounts->getDefault();
$viewRange = $this->preferences->get('viewRange','1M');
$viewRangeValue = $viewRange->data;
// pref:
$frontpage = $this->preferences->get('frontpageAccounts', []);
return View::make('preferences.index')->with('accounts', $accounts)->with('frontpageAccounts', $frontpage);
return View::make('preferences.index')->with('accounts', $accounts)->with('frontpageAccounts', $frontpage)->with('viewRange',$viewRangeValue);
}
public function postIndex()
{
// frontpage accounts
$frontpageAccounts = [];
foreach(Input::get('frontpageAccounts') as $id) {
$frontpageAccounts[] = intval($id);
}
$this->preferences->set('frontpageAccounts',$frontpageAccounts);
// view range:
$this->preferences->set('viewRange',Input::get('viewRange'));
// forget session values:
Session::forget('start');
Session::forget('end');
Session::forget('range');
Session::flash('success', 'Preferences saved!');
return Redirect::route('preferences');
}

View File

@@ -0,0 +1,26 @@
<?php
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
class TransactionController extends BaseController {
protected $accounts;
public function __construct(ARI $accounts) {
$this->accounts = $accounts;
View::share('menu','home');
}
public function createWithdrawal() {
// get accounts with names and id's.
$accounts =$this->accounts->getActiveDefaultAsSelectList();
return View::make('transactions.withdrawal')->with('accounts',$accounts);
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
class CreateSessionTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sessions', function($t)
{
$t->string('id')->unique();
$t->text('payload');
$t->integer('last_activity');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('sessions');
}
}

View File

@@ -17,25 +17,68 @@ class Toolkit implements ToolkitInterface
public static function getDateRange()
{
$preferences = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
$viewRange = $preferences->get('viewRange', 'week');
$viewRange = $preferences->get('viewRange', '1M');
// as you can see, this method now only supports "right now":
$now = new \Carbon\Carbon;
$start = clone $now;
$end = clone $now;
// default range:
$range = $viewRange->data;
// update range if session has something:
if (!is_null(\Session::get('range'))) {
$range = \Session::get('range');
}
switch ($viewRange->data) {
case 'week':
// update view range if the input has something:
if (!is_null(\Input::get('range'))) {
$range = \Input::get('range');
}
// switch $range, update range or something:
$today = new \Carbon\Carbon;
$start = clone $today;
$end = clone $today;
switch ($range) {
case 'custom':
// when range is custom AND input, we ignore $today
if (\Input::get('start') && \Input::get('end')) {
$start = new \Carbon\Carbon(\Input::get('start'));
$end = new \Carbon\Carbon(\Input::get('end'));
} else {
$start = \Session::get('start');
$end = \Session::get('end');
}
break;
case '1D':
$start->startOfDay();
$end->endOfDay();
break;
case '1W':
$start->startOfWeek();
$end->endOfWeek();
break;
default:
case 'month':
case '1M':
$start->startOfMonth();
$end->endOfMonth();
break;
case '3M':
$start->firstOfQuarter();
$end->lastOfQuarter();
break;
case '6M':
if (intval($today->format('m')) >= 7) {
$start->startOfYear()->addMonths(6);
$end->endOfYear();
} else {
$start->startOfYear();
$end->startOfYear()->addMonths(6);
}
break;
}
// save in session:
\Session::put('start', $start);
\Session::put('end', $end);
\Session::put('range', $range);
// and return:
return [$start, $end];

View File

@@ -10,12 +10,21 @@ interface AccountRepositoryInterface
public function count();
public function get();
public function getBeneficiaries();
public function find($id);
public function getByIds($ids);
public function getDefault();
public function getActiveDefault();
public function getActiveDefaultAsSelectList();
public function store($data);
public function storeWithInitialBalance($data,\Carbon\Carbon $date, $amount = 0);
public function storeWithInitialBalance($data, \Carbon\Carbon $date, $amount = 0);
}

View File

@@ -16,6 +16,16 @@ class EloquentAccountRepository implements AccountRepositoryInterface
return \Auth::user()->accounts()->with('accounttype')->get();
}
public function getBeneficiaries() {
$list = \Auth::user()->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id'
)
->where('account_types.description', 'Beneficiary account')->where('accounts.active', 1)
->get(['accounts.*']);
return $list;
}
public function find($id)
{
return \Auth::user()->accounts()->where('id', $id)->first();
@@ -42,6 +52,21 @@ class EloquentAccountRepository implements AccountRepositoryInterface
->get(['accounts.*']);
}
public function getActiveDefaultAsSelectList()
{
$list = \Auth::user()->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id'
)
->where('account_types.description', 'Default account')->where('accounts.active', 1)
->get(['accounts.*']);
$return = [];
foreach ($list as $entry) {
$return[intval($entry->id)] = $entry->name;
}
return $return;
}
public function count()
{
return \Auth::user()->accounts()->count();

View File

@@ -9,6 +9,8 @@ interface ComponentRepositoryInterface
public function count();
public function get();
public function store($data);
}

View File

@@ -13,10 +13,15 @@ class EloquentComponentRepository implements ComponentRepositoryInterface
public function count()
{
return \Auth::user()->accounts()->count();
return \Auth::user()->components()->count();
}
public function get() {
die('no impl');
}
public function store($data)
{

View File

@@ -145,7 +145,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
// lets make this simple.
$types = [];
foreach (\TransactionType::whereIn('type', ['Deposit', 'Withdrawal'])->get() as $t) {
foreach (\TransactionType::whereIn('type', ['Withdrawal'])->get() as $t) {
$types[] = $t->id;
}
unset($t);
@@ -163,6 +163,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
->whereIn('transaction_type_id', $types)
->get(['transaction_journals.*']);
unset($types);
$result = [];
foreach ($journals as $journal) {
@@ -196,7 +197,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
// lets make this simple.
$types = [];
foreach (\TransactionType::whereIn('type', ['Deposit', 'Withdrawal'])->get() as $t) {
foreach (\TransactionType::whereIn('type', ['Withdrawal'])->get() as $t) {
$types[] = $t->id;
}
unset($t);

View File

@@ -42,9 +42,9 @@ class Account extends Elegant
{
$date = is_null($date) ? new \Carbon\Carbon : $date;
return $this->transactions()
return floatval($this->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount');
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount'));
}
public function transactions()

View File

@@ -1,6 +1,6 @@
<table class="table table-bordered table-striped">
<tr>
<th style="width:25px;">&nbsp;</th>
<th>&nbsp;</th>
<th style="width:30%;">Name</th>
<th>Current balance</th>
</tr>

View File

@@ -7,6 +7,24 @@
<small>What's playing?</small>
@endif
</h1>
<form role="form" class="form-horizontal">
<div class="input-group">
<?php $r = Session::get('range','1M');?>
<span class="input-group-btn input-group-btn">
<button name="range" value="1D" class="btn btn-default @if($r=='1D') btn-info @endif btn-sm" type="submit">1D</button>
<button name="range" value="1W" class="btn btn-default @if($r=='1W') btn-info @endif btn-sm" type="submit">1W</button>
<button name="range" value="1M" class="btn btn-default @if($r=='1M') btn-info @endif btn-sm" type="submit">1M</button>
<button name="range" value="3M" class="btn btn-default @if($r=='3M') btn-info @endif btn-sm" type="submit">3M</button>
<button name="range" value="6M" class="btn btn-default @if($r=='6M') btn-info @endif btn-sm" type="submit">6M</button>
</span>
<input value="{{Session::get('start')->format('Y-m-d')}}" name="start" type="date" style="width:15%;" class="form-control input-sm">
<input value="{{Session::get('end')->format('Y-m-d')}}" name="end" type="date" style="width:15%;" class="form-control input-sm">
<button class="btn btn-default btn-sm @if($r=='custom') btn-info @endif" type="submit" name="range" value="custom">Custom</button>
</div>
</form>
</div>
</div>
@if($count == 0)
@@ -39,8 +57,7 @@
<div class="row">
@foreach($accounts as $index => $account)
<div class="col-lg-6">
<h4>{{{$account->name}}} chart</h4>
<div id="chart_{{{$account->id}}}" data-id="{{{$account->id}}}" class="homeChart" data-title="{{{$account->name}}}"></div>
<div id="chart_{{{$account->id}}}" data-id="{{{$account->id}}}" style="width:100%;" class="homeChart" data-title="{{{$account->name}}}"></div>
<p>
Go to <a href="#" title="Overview for {{{$account->name}}}">{{{$account->name}}}</a>
</p>
@@ -60,7 +77,7 @@
@include('transactions.journals',['journals' => $account->transactionList])
</div>
@if($index % 2 == 1)
</div><div class="row" style="border-top:1px #eee solid;">
</div><div class="row">
@endif
@endforeach
</div>
@@ -80,16 +97,13 @@
<!-- Beneficiaries, categories and budget pie charts: -->
<div class="row">
<div class="col-lg-4 col-sm-6 col-md-6">
<h4>Beneficiaries</h4>
<div id="beneficiaryChart"></div>
<div style="width:80%;margin:0 auto;" id="beneficiaryChart"></div>
</div>
<div class="col-lg-4 col-sm-6 col-md-6">
<h4>Categories</h4>
<div id="categoryChart"></div>
<div style="width:80%;margin:0 auto;" id="categoryChart"></div>
</div>
<div class="col-lg-4 col-sm-6 col-md-6">
<h4>Budgets</h4>
<div id="budgetChart"></div>
<div style="width:80%;margin:0 auto;" id="budgetChart"></div>
</div>
</div>
<br /><br /><br /><br /><br />
@@ -99,7 +113,6 @@
@stop
@section('scripts')
<script src="https://www.google.com/jsapi"></script>
<script src="assets/javascript/charts.js"></script>
<script src="assets/javascript/index.js"></script>
<script src="assets/javascript/highcharts.js"></script>
<script src="assets/javascript/index.new.js"></script>
@stop

View File

@@ -9,6 +9,7 @@
<!-- Bootstrap -->
<link href="assets/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/css/site.css" rel="stylesheet">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
@@ -28,6 +29,7 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="assets/javascript/bootstrap3-typeahead.min.js"></script>
@yield('scripts')
</body>
</html>

View File

@@ -9,13 +9,15 @@
</div>
</div>
<!-- form -->
{{Form::open(['class' => 'form-horizontal'])}}
<!-- home screen accounts -->
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h3>Home screen accounts</h3>
<p class="text-info">Which accounts should be displayed on the home page?</p>
<!-- form -->
{{Form::open(['class' => 'form-horizontal'])}}
@foreach($accounts as $account)
<div class="form-group">
<div class="col-sm-10">
@@ -31,15 +33,74 @@
</div>
</div>
@endforeach
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default">Save accounts</button>
</div>
</div>
</form>
</div>
</div>
<!-- home screen accounts -->
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h3>Home view range</h3>
<p class="text-info">By default, Firefly will show you one month of data.</p>
<div class="radio">
<label>
<input type="radio" name="viewRange" value="1D" @if($viewRange == '1D') checked @endif>
One day
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="viewRange" value="1W" @if($viewRange == '1W') checked @endif>
One week
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="viewRange" value="1M" @if($viewRange == '1M') checked @endif>
One month
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="viewRange" value="3M" @if($viewRange == '3M') checked @endif>
Three months
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="viewRange" value="6M" @if($viewRange == '6M') checked @endif>
Six months
</label>
</div>
</div>
</div>
<!-- submit button -->
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h3>Submit</h3>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default">Save settings</button>
</div>
</div>
</div>
</div>
<!-- form close -->
{{Form::close()}}
@stop
@section('scripts')
@stop

View File

@@ -0,0 +1,106 @@
@extends('layouts.default')
@section('content')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h1>Firefly
<small>Add a new withdrawal</small>
</h1>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-12">
<p class="text-info">
Technically speaking, withdrawals, deposits and transfers are all transactions, moving money from
account <em>A</em> to account <em>B</em>.
</p>
<p class="text-info">
A withdrawal is when you spend money on something, moving an amount to a <em>beneficiary</em>.
</p>
</div>
</div>
{{Form::open(['class' => 'form-horizontal'])}}
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-12">
<h4>Mandatory fields</h4>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Description</label>
<div class="col-sm-8">
<input type="text" name="description" value="{{{Input::old('description')}}}" autocomplete="off" class="form-control" placeholder="Description" />
</div>
</div>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Account</label>
<div class="col-sm-8">
{{Form::select('account_id',$accounts,Input::old('account_id'),['class' => 'form-control'])}}
</div>
</div>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Beneficiary</label>
<div class="col-sm-8">
<input type="text" name="beneficiary" value="{{{Input::old('beneficiary')}}}" autocomplete="off" class="form-control" placeholder="Beneficiary" />
<span class="help-block">This field will auto-complete your existing beneficiaries (if any), but you can type freely to create new ones.</span>
</div>
</div>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Amount spent</label>
<div class="col-sm-8">
<input type="number" min="0.01" step="any" class="form-control" />
</div>
</div>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Date</label>
<div class="col-sm-8">
<input type="date" class="form-control" />
</div>
</div>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">&nbsp;</label>
<div class="col-sm-8">
<input type="submit" name="submit" value="Create withdrawal" class="btn btn-info" />
</div>
</div>
</div>
<div class="col-lg-6 col-md-12 col-sm-12">
<h4>Optional fields</h4>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Budget</label>
<div class="col-sm-8">
<select class="form-control">
<option>1</option>
</select>
<span class="help-block">Select one of your budgets to make this transaction a part of it.</span>
</div>
</div>
<div class="form-group">
<label for="account" class="col-sm-4 control-label">Category</label>
<div class="col-sm-8">
<input type="text" name="category" value="" autocomplete="off" class="form-control" placeholder="Category" />
<span class="help-block">Add more fine-grained information to this transaction by entering a category.
Like the beneficiary-field, this field will auto-complete existing categories but can also be used
to create new ones.
</span>
</div>
</div>
</div>
@stop
@section('scripts')
<script type="text/javascript" src="assets/javascript/withdrawal.js"></script>
@stop