diff --git a/app/controllers/ChartController.php b/app/controllers/ChartController.php index 181cf5ff25..c5e1d19549 100644 --- a/app/controllers/ChartController.php +++ b/app/controllers/ChartController.php @@ -1,5 +1,6 @@ _accounts = $accounts; $this->_journals = $journals; + $this->_preferences = $preferences; } /** @@ -34,98 +37,139 @@ class ChartController extends BaseController $current = clone $start; $return = []; $account = null; + $today = new Carbon\Carbon; if (!is_null($accountId)) { + /** @var \Account $account */ $account = $this->_accounts->find($accountId); } if (is_null($account)) { - $accounts = $this->_accounts->getActiveDefault(); + $pref = $this->_preferences->get('frontpageAccounts', []); + if ($pref->data == []) { + $accounts = $this->_accounts->getActiveDefault(); + } else { + $accounts = $this->_accounts->getByIds($pref->data); + } foreach ($accounts as $account) { - $return[] = ['name' => $account->name, 'data' => []]; + $return[] = ['name' => $account->name, 'id' => 'acc-' . $account->id, 'data' => []]; + } while ($current <= $end) { - // loop accounts: foreach ($accounts as $index => $account) { - $return[$index]['data'][] = [$current->timestamp * 1000, $account->balance(clone $current)]; + + + if ($current > $today) { + $return[$index]['data'][] = [$current->timestamp * 1000, $account->predict(clone $current)]; + } else { + $return[$index]['data'][] = [$current->timestamp * 1000, $account->balance(clone $current)]; + } } $current->addDay(); } } else { - $return[0] = ['name' => $account->name, 'data' => []]; + $return[0] = ['name' => $account->name, 'id' => $account->id, 'data' => []]; while ($current <= $end) { + if ($current > $today) { + $return[0]['data'][] = [$current->timestamp * 1000, $account->predict(clone $current)]; + } else { + $return[0]['data'][] = [$current->timestamp * 1000, $account->balance(clone $current)]; + } - $return[0]['data'][] = [$current->timestamp * 1000, $account->balance(clone $current)]; $current->addDay(); } - } +// // add an error bar as experiment: +// foreach($return as $index => $serie) { +// $err = [ +// 'type' => 'errorbar', +// 'name' => $serie['name'].' pred', +// 'linkedTo' => $serie['id'], +// 'data' => [] +// ]; +// foreach($serie['data'] as $entry) { +// $err['data'][] = [$entry[0],10,300]; +// } +// $return[] = $err; +// } + + return Response::json($return); } /** - * Get all budgets used in transaction(journals) this period: + * Return some beneficiary info for an account and a date. + * + * @param $name + * @param $day + * @param $month + * @param $year */ - public function homeBudgets() + public function homeAccountInfo($name, $day, $month, $year) { - list($start, $end) = tk::getDateRange(); - $data = [ - 'type' => 'pie', - 'name' => 'Expense: ', - 'data' => [] - ]; + $account = $this->_accounts->findByName($name); + $result = []; + $sum = 0; + if ($account) { + $date = \Carbon\Carbon::createFromDate($year, $month, $day); + $journals = $this->_journals->getByAccountAndDate($account, $date); - $result = $this->_journals->homeBudgetChart($start, $end); - - foreach ($result as $name => $amount) { - $data['data'][] = [$name, $amount]; + // loop all journals: + foreach ($journals as $journal) { + foreach ($journal->transactions as $transaction) { + $name = $transaction->account->name; + if ($transaction->account->id != $account->id) { + $result[$name] = isset($result[$name]) ? $result[$name] + floatval($transaction->amount) + : floatval($transaction->amount); + $sum += floatval($transaction->amount); + } + } + } } - return Response::json([$data]); - + return View::make('charts.info')->with('rows', $result)->with('sum', $sum); } - /** - * Get all categories used in transaction(journals) this period. - */ - public function homeCategories() - { + public function homeCategories() { list($start, $end) = tk::getDateRange(); + $account = null; + $result = []; + // grab all transaction journals in this period: + $journals = $this->_journals->getByDateRange($start,$end); - $result = $this->_journals->homeCategoryChart($start, $end); - $data = [ - 'type' => 'pie', - 'name' => 'Amount: ', - 'data' => [] - ]; + $result = []; + foreach ($journals as $journal) { + // has to be one: + + if (!isset($journal->transactions[0])) { + throw new FireflyException('Journal #' . $journal->id . ' has ' . count($journal->transactions) + . ' transactions!'); + } + $transaction = $journal->transactions[0]; + $amount = floatval($transaction->amount); + + // get budget from journal: + $budget = $journal->categories()->first(); + $budgetName = is_null($budget) ? '(no category)' : $budget->name; + + $result[$budgetName] = isset($result[$budgetName]) ? $result[$budgetName] + floatval($amount) : $amount; - foreach ($result as $name => $amount) { - $data['data'][] = [$name, $amount]; } - return Response::json([$data]); + unset($journal, $transaction, $budget, $amount); + + // sort + arsort($result); + $chartData = [ + ]; + foreach($result as $name => $value) { + $chartData[] = [$name, $value]; + } + + + + return Response::json($chartData); } - - /** - * get all beneficiaries used in transaction(journals) this period. - */ - public function homeBeneficiaries() - { - list($start, $end) = tk::getDateRange(); - $data = [ - 'type' => 'pie', - 'name' => 'Amount: ', - 'data' => [] - ]; - - $result = $this->_journals->homeBeneficiaryChart($start, $end); - - foreach ($result as $name => $amount) { - $data['data'][] = [$name, $amount]; - } - return Response::json([$data]); - - } -} \ No newline at end of file +} \ No newline at end of file diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php index 97f31f5106..948494bf1d 100644 --- a/app/controllers/HomeController.php +++ b/app/controllers/HomeController.php @@ -30,24 +30,10 @@ class HomeController extends BaseController */ public function index() { - // get list setting: - $pref = $this->_preferences->get('frontpageAccounts', []); - // get the accounts to display on the home screen: $count = $this->_accounts->count(); - if ($pref->data == []) { - $list = $this->_accounts->getActiveDefault(); - } else { - $list = $this->_accounts->getByIds($pref->data); - } - - // get transactions for each account: - foreach ($list as $account) { - $account->transactionList = $this->_journal->getByAccount($account, 10); - } - // build the home screen: - return View::make('index')->with('count', $count)->with('accounts', $list); + return View::make('index')->with('count', $count); } } \ No newline at end of file diff --git a/app/controllers/MigrationController.php b/app/controllers/MigrationController.php index cecad119ed..4b87445824 100644 --- a/app/controllers/MigrationController.php +++ b/app/controllers/MigrationController.php @@ -40,6 +40,8 @@ class MigrationController extends BaseController exit(); } } + echo 'home'; + exit(); } /** diff --git a/app/database/migrations/2014_07_17_183717_create_limits_table.php b/app/database/migrations/2014_07_17_183717_create_limits_table.php new file mode 100644 index 0000000000..7a91836c49 --- /dev/null +++ b/app/database/migrations/2014_07_17_183717_create_limits_table.php @@ -0,0 +1,41 @@ +increments('id'); + $table->timestamps(); + $table->integer('component_id')->unsigned(); + $table->date('startdate'); + $table->date('enddate'); + $table->decimal('amount',10,2); + + // connect component + $table->foreign('component_id') + ->references('id')->on('components') + ->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('limits'); + } + +} diff --git a/app/lib/Firefly/Storage/TransactionJournal/EloquentTransactionJournalRepository.php b/app/lib/Firefly/Storage/TransactionJournal/EloquentTransactionJournalRepository.php index 5ee1a572cb..598ef2489d 100644 --- a/app/lib/Firefly/Storage/TransactionJournal/EloquentTransactionJournalRepository.php +++ b/app/lib/Firefly/Storage/TransactionJournal/EloquentTransactionJournalRepository.php @@ -167,127 +167,16 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito } - public function homeBudgetChart(\Carbon\Carbon $start, \Carbon\Carbon $end) - { - return $this->homeComponentChart($start, $end, 'Budget'); - } - - public function homeComponentChart(\Carbon\Carbon $start, \Carbon\Carbon $end, $chartType) - { - - // lets make this simple. - $types = []; - foreach (\TransactionType::whereIn('type', ['Withdrawal'])->get() as $t) { - $types[] = $t->id; - } - unset($t); - - // get all journals, partly filtered: - $journals = \TransactionJournal:: - with( - ['components' => function ($q) use ($chartType) { - $q->where('class', $chartType); - }, 'transactions' => function ($q) { - $q->where('amount', '>', 0); - }] - ) - ->after($start)->before($end) - ->where('completed', 1) - ->whereIn('transaction_type_id', $types) - ->get(['transaction_journals.*']); - unset($types); - $result = []; - - - foreach ($journals as $journal) { - // has to be one: - if (!isset($journal->transactions[0])) { - throw new FireflyException('Journal #' . $journal->id . ' has ' . count($journal->transactions) - . ' transactions!'); - } - $transaction = $journal->transactions[0]; - $amount = floatval($transaction->amount); - - - // MIGHT be one: - $budget = isset($journal->components[0]) ? $journal->components[0] : null; - if (!is_null($budget)) { - $name = $budget->name; - } else { - $name = '(no budget)'; - } - $result[$name] = isset($result[$name]) ? $result[$name] + $amount : $amount; - - } - unset($journal, $transaction, $budget, $name, $amount); - - // sort - arsort($result); - - return $result; - } - - public function homeCategoryChart(\Carbon\Carbon $start, \Carbon\Carbon $end) - { - return $this->homeComponentChart($start, $end, 'Category'); - } - - public function homeBeneficiaryChart(\Carbon\Carbon $start, \Carbon\Carbon $end) - { - $result = []; - - // lets make this simple. - $types = []; - foreach (\TransactionType::whereIn('type', ['Withdrawal'])->get() as $t) { - $types[] = $t->id; - } - unset($t); - - // account type we want to see: - $accountType = \AccountType::where('description', 'Beneficiary account')->first(); - $accountTypeID = $accountType->id; - - // get all journals, partly filtered: - $journals = \TransactionJournal:: - with( - ['transactions', 'transactions.account' => function ($q) use ($accountTypeID) { - $q->where('account_type_id', $accountTypeID); - }] - ) - ->after($start)->before($end) - ->whereIn('transaction_type_id', $types) - ->orderBy('date', 'DESC') - ->orderBy('id', 'DESC') - ->get(['transaction_journals.*']); - foreach ($journals as $journal) { - foreach ($journal->transactions as $t) { - if (!is_null($t->account)) { - $name = $t->account->name; - $amount = floatval($t->amount) < 0 ? floatval($t->amount) * -1 : floatval($t->amount); - - $result[$name] = isset($result[$name]) ? $result[$name] + $amount : $amount; - } - } - } - // sort result: - arsort($result); - - - return $result; - } - public function getByAccount(\Account $account, $count = 25) { $accountID = $account->id; - $query = \TransactionJournal:: - with( - [ - 'transactions', - 'transactioncurrency', - 'transactiontype' - ] - ) - ->take($count) + $query = \Auth::user()->transactionjournals()->with( + [ + 'transactions', + 'transactioncurrency', + 'transactiontype' + ] + ) ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->where('accounts.id', $accountID) @@ -298,5 +187,51 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito return $query; } + public function getByDateRange(\Carbon\Carbon $start, \Carbon\Carbon $end) + { + // lets make this simple. + $types = []; + foreach (\TransactionType::whereIn('type', ['Withdrawal'])->get() as $t) { + $types[] = $t->id; + } + unset($t); + + // get all journals, partly filtered: + $journals = \TransactionJournal:: + with( + ['components', 'transactions' => function ($q) { + $q->where('amount', '>', 0); + }] + ) + ->after($start)->before($end) + ->where('completed', 1) + ->whereIn('transaction_type_id', $types) + ->get(['transaction_journals.*']); + unset($types); + return $journals; + } + + public function getByAccountAndDate(\Account $account, \Carbon\Carbon $date) + { + $accountID = $account->id; + $query = \Auth::user()->transactionjournals()->with( + [ + 'transactions', + 'transactions.account', + 'transactioncurrency', + 'transactiontype' + ] + ) + ->distinct() + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->where('transactions.account_id', $accountID) + ->where('transaction_journals.date', $date->format('Y-m-d')) + ->orderBy('transaction_journals.date', 'DESC') + ->orderBy('transaction_journals.id', 'DESC') + ->get(['transaction_journals.*']); + return $query; + } + } \ No newline at end of file diff --git a/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php b/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php index 56ef614561..9963dae8a4 100644 --- a/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php +++ b/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php @@ -13,12 +13,8 @@ interface TransactionJournalRepositoryInterface public function getByAccount(\Account $account, $count = 25); - public function homeBudgetChart(\Carbon\Carbon $start, \Carbon\Carbon $end); + public function getByAccountAndDate(\Account $account, \Carbon\Carbon $date); - public function homeCategoryChart(\Carbon\Carbon $start, \Carbon\Carbon $end); - - public function homeBeneficiaryChart(\Carbon\Carbon $start, \Carbon\Carbon $end); - - public function homeComponentChart(\Carbon\Carbon $start, \Carbon\Carbon $end, $chartType); + public function getByDateRange(\Carbon\Carbon $start, \Carbon\Carbon $end); } \ No newline at end of file diff --git a/app/models/Account.php b/app/models/Account.php index cb4e23754d..8e5b834bb1 100644 --- a/app/models/Account.php +++ b/app/models/Account.php @@ -88,10 +88,14 @@ class Account extends Ardent ->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 predict(\Carbon\Carbon $date) { + return null; + } + /** * Transactions. * diff --git a/app/models/Component.php b/app/models/Component.php index aae42549d2..a06abc3215 100644 --- a/app/models/Component.php +++ b/app/models/Component.php @@ -42,6 +42,10 @@ class Component extends Firefly\Database\SingleTableInheritanceEntity return $this->belongsToMany('Transaction'); } + public function limits() { + return $this->belongsTo('Limit'); + } + public function transactionjournals() { return $this->belongsToMany('TransactionJournal'); diff --git a/app/models/Limit.php b/app/models/Limit.php new file mode 100644 index 0000000000..5ffef56c58 --- /dev/null +++ b/app/models/Limit.php @@ -0,0 +1,41 @@ + 'required|exists:components,id', + 'startdate' => 'required|date', + 'enddate' => 'required|date', + 'amount' => 'numeric|required|min:0.01' + + ]; + + public static $factory + = [ + 'component_id' => 'factory|Budget', + 'startdate' => 'date', + 'enddate' => 'date', + 'amount' => '100' + ]; + + public function component() + { + return $this->belongsTo('Component'); + } + + public function budget() + { + return $this->belongsTo('Budget', 'component_id'); + } + + public function getDates() + { + return ['created_at', 'updated_at', 'startdate', 'enddate']; + } + + +} \ No newline at end of file diff --git a/app/routes.php b/app/routes.php index ba0d8f8e03..c623f869e1 100644 --- a/app/routes.php +++ b/app/routes.php @@ -7,9 +7,9 @@ Route::group(['before' => 'auth'], function () { // chart controller Route::get('/chart/home/account/{account?}', ['uses' => 'ChartController@homeAccount', 'as' => 'chart.home']); - Route::get('/chart/home/budgets', ['uses' => 'ChartController@homeBudgets', 'as' => 'chart.budgets']); - Route::get('/chart/home/beneficiaries', ['uses' => 'ChartController@homeBeneficiaries', 'as' => 'chart.beneficiaries']); Route::get('/chart/home/categories', ['uses' => 'ChartController@homeCategories', 'as' => 'chart.categories']); + Route::get('/chart/home/info/{account}/{day}/{month}/{year}', ['uses' => 'ChartController@homeAccountInfo', 'as' => 'chart.info']); + // preferences controller Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']); @@ -26,6 +26,9 @@ Route::group(['before' => 'auth'], function () { Route::get('/accounts/create', ['uses' => 'AccountController@create', 'as' => 'accounts.create']); Route::get('/accounts/{account}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']); + // budget controller + Route::get('/bugets',['uses' => 'BudgetController@index','as' => 'budgets.index']); + // JSON controller: Route::get('/json/beneficiaries', ['uses' => 'JsonController@beneficiaries', 'as' => 'json.beneficiaries']); Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']); diff --git a/app/tests/controllers/HomeControllerTest.php b/app/tests/controllers/HomeControllerTest.php index 62c42829f8..11d770ce15 100644 --- a/app/tests/controllers/HomeControllerTest.php +++ b/app/tests/controllers/HomeControllerTest.php @@ -13,64 +13,12 @@ class HomeControllerTest extends TestCase View::shouldReceive('share'); View::shouldReceive('make')->with('index')->once()->andReturn(\Mockery::self()) ->shouldReceive('with')->once() // Pass a 'with' parameter - ->with('count', 0) - ->andReturn(Mockery::self()) - ->shouldReceive('with')->once() // another 'with' parameter. - ->with('accounts',[]) - ->andReturn(Mockery::self()) - ; + ->with('count', 0); Auth::shouldReceive('check')->andReturn(true); // mock account repository $accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface'); $accounts->shouldReceive('count')->andReturn(0); - $accounts->shouldReceive('getActiveDefault')->andReturn([]); - - $preferences = $this->mock('Firefly\Helper\Preferences\PreferencesHelperInterface'); - $preferences->shouldReceive('get')->with('frontpageAccounts',[])->andReturn(new \Preference)->once(); - - // call - $this->call('GET', '/'); - - // test - $this->assertResponseOk(); - } - - public function testIndexWithAccount() { - - // mock Account - $account = $this->mock('Account'); - $account->shouldReceive('setAttribute')->with('transactionList',[]); - - // mock account repository - $accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface'); - $accounts->shouldReceive('count')->andReturn(0); - $accounts->shouldReceive('getByIds')->andReturn([$account]); - - // mock: - View::shouldReceive('share'); - View::shouldReceive('make')->with('index')->once()->andReturn(\Mockery::self()) - ->shouldReceive('with')->once() // Pass a 'with' parameter - ->with('count', 0) - ->andReturn(Mockery::self()) - ->shouldReceive('with')->once() // another 'with' parameter. - ->with('accounts',[$account]) - ->andReturn(Mockery::self()) - ; - - - - // mock transaction journal - $tj = $this->mock('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); - $tj->shouldReceive('getByAccount')->with($account,10)->andReturn([]); - - // mock preferences helper: - $pref = $this->mock('Preference'); - $pref->shouldReceive('getAttribute', 'data')->andReturn([1]); - - - $preferences = $this->mock('Firefly\Helper\Preferences\PreferencesHelperInterface'); - $preferences->shouldReceive('get')->with('frontpageAccounts',[])->andReturn($pref)->once(); // call $this->call('GET', '/'); diff --git a/app/views/charts/info.blade.php b/app/views/charts/info.blade.php new file mode 100644 index 0000000000..8bcf421910 --- /dev/null +++ b/app/views/charts/info.blade.php @@ -0,0 +1,12 @@ +
| Total | +{{mf($sum*-1)}} | +
|---|---|
| {{{$name}}} | +{{mf($amount*-1)}} | +
- Go to {{{$account->name}}} -
- +