mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Merge branch 'release/3.3.8'
This commit is contained in:
commit
23faef845c
@ -1,5 +1,5 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
|
@ -1,4 +1,4 @@
|
||||
Firefly III (v3.3.7)
|
||||
Firefly III (v3.3.8)
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/JC5/firefly-iii)
|
||||
|
@ -51,14 +51,7 @@ class ConnectJournalToPiggyBank
|
||||
return;
|
||||
}
|
||||
Log::debug('Found a piggy bank');
|
||||
$amount = 0;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if ($transaction->account_id === $piggyBank->account_id) {
|
||||
// this transaction is the relevant one.
|
||||
$amount = floatval($transaction->amount);
|
||||
}
|
||||
}
|
||||
$amount = $journal->amount;
|
||||
Log::debug('Amount: ' . $amount);
|
||||
if ($amount == 0) {
|
||||
return;
|
||||
|
@ -45,17 +45,8 @@ class UpdateJournalConnection
|
||||
if (is_null($repetition)) {
|
||||
return;
|
||||
}
|
||||
$amount = 0;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions()->get() as $transaction) {
|
||||
if ($transaction->account_id === $piggyBank->account_id) {
|
||||
// this transaction is the relevant one.
|
||||
$amount = floatval($transaction->amount);
|
||||
}
|
||||
}
|
||||
|
||||
// update current repetition:
|
||||
$diff = $amount - $event->amount;
|
||||
$amount = $journal->amount;
|
||||
$diff = $amount - $event->amount;// update current repetition
|
||||
|
||||
$repetition->currentamount += $diff;
|
||||
$repetition->save();
|
||||
|
85
app/Helpers/Help/Help.php
Normal file
85
app/Helpers/Help/Help.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
use Cache;
|
||||
use ErrorException;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Log;
|
||||
use Route;
|
||||
|
||||
/**
|
||||
* Class Help
|
||||
*
|
||||
* @package FireflyIII\Helpers\Help
|
||||
*/
|
||||
class Help implements HelpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromCache($key)
|
||||
{
|
||||
return Cache::get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromGithub($route)
|
||||
{
|
||||
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md';
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => $route,
|
||||
];
|
||||
try {
|
||||
$content['text'] = file_get_contents($uri);
|
||||
} catch (ErrorException $e) {
|
||||
Log::error(trim($e->getMessage()));
|
||||
}
|
||||
if (strlen(trim($content['text'])) == 0) {
|
||||
$content['text'] = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
$converter = new CommonMarkConverter();
|
||||
$content['text'] = $converter->convertToHtml($content['text']);
|
||||
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasRoute($route)
|
||||
{
|
||||
return Route::has($route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $title
|
||||
* @param array $content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putInCache($route, array $content)
|
||||
{
|
||||
Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week.
|
||||
Cache::put('help.' . $route . '.title', $content['title'], 10080);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inCache($route)
|
||||
{
|
||||
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||
}
|
||||
}
|
46
app/Helpers/Help/HelpInterface.php
Normal file
46
app/Helpers/Help/HelpInterface.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
/**
|
||||
* Interface HelpInterface
|
||||
*
|
||||
* @package FireflyIII\Helpers\Help
|
||||
*/
|
||||
interface HelpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromCache($key);
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasRoute($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromGithub($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param array $content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putInCache($route, array $content);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inCache($route);
|
||||
}
|
@ -60,23 +60,21 @@ class ReportHelper implements ReportHelperInterface
|
||||
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
|
||||
}
|
||||
)
|
||||
->get(['budgets.*', 'budget_limits.amount as amount']);
|
||||
->get(['budgets.*', 'budget_limits.amount as queryAmount']);
|
||||
|
||||
$budgets = Steam::makeArray($set);
|
||||
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
|
||||
$amounts = Steam::makeArray($amountSet);
|
||||
$budgets = Steam::mergeArrays($budgets, $amounts);
|
||||
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
|
||||
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
|
||||
$budgets[0]['name'] = 'No budget';
|
||||
$budgets = Steam::makeArray($set);
|
||||
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
|
||||
$amounts = Steam::makeArray($amountSet);
|
||||
$budgets = Steam::mergeArrays($budgets, $amounts);
|
||||
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
|
||||
$budgets[0]['queryAmount'] = isset($budgets[0]['queryAmount']) ? $budgets[0]['queryAmount'] : 0.0;
|
||||
$budgets[0]['name'] = 'No budget';
|
||||
|
||||
// find transactions to shared asset accounts, which are without a budget by default:
|
||||
// which is only relevant when shared asset accounts are hidden.
|
||||
if ($showSharedReports === false) {
|
||||
$transfers = $query->sharedExpenses($start, $end);
|
||||
foreach ($transfers as $transfer) {
|
||||
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
|
||||
}
|
||||
$transfers = $query->sharedExpenses($start, $end)->sum('queryAmount');
|
||||
$budgets[0]['spent'] += floatval($transfers) * -1;
|
||||
}
|
||||
|
||||
return $budgets;
|
||||
|
@ -96,7 +96,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
->get(
|
||||
[
|
||||
'transaction_journals.*',
|
||||
'transactions.amount'
|
||||
'transactions.amount as queryAmount'
|
||||
]
|
||||
);
|
||||
|
||||
@ -111,17 +111,11 @@ class ReportQuery implements ReportQueryInterface
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
* @return float
|
||||
*/
|
||||
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
$set = $this->balancedTransactionsList($account, $start, $end);
|
||||
$sum = 0;
|
||||
foreach ($set as $entry) {
|
||||
$sum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
return $sum;
|
||||
return floatval($this->balancedTransactionsList($account, $start, $end)->sum('queryAmount'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +172,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
{
|
||||
$query = $this->queryJournalsNoBudget($account, $start, $end);
|
||||
|
||||
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `amount`')]);
|
||||
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `queryAmount`')]);
|
||||
|
||||
}
|
||||
|
||||
@ -196,7 +190,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
{
|
||||
$query = $this->queryJournalsNoBudget($account, $start, $end);
|
||||
|
||||
return $query->get(['budgets.name', 'transactions.amount', 'transaction_journals.*']);
|
||||
return $query->get(['budgets.name', 'transactions.amount as queryAmount', 'transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,7 +238,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
'transaction_journals.description',
|
||||
'transaction_journals.encrypted',
|
||||
'transaction_types.type',
|
||||
DB::Raw('SUM(`t_to`.`amount`) as `amount`'),
|
||||
DB::Raw('SUM(`t_to`.`amount`) as `queryAmount`'),
|
||||
'transaction_journals.date',
|
||||
't_from.account_id as account_id',
|
||||
'ac_from.name as name',
|
||||
@ -254,7 +248,6 @@ class ReportQuery implements ReportQueryInterface
|
||||
|
||||
$data->each(
|
||||
function (Model $object) {
|
||||
// $object->description = intval($object->encrypted);
|
||||
$object->name = intval($object->account_encrypted) == 1 ? Crypt::decrypt($object->name) : $object->name;
|
||||
}
|
||||
);
|
||||
@ -335,9 +328,9 @@ class ReportQuery implements ReportQueryInterface
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('amount');
|
||||
->orderBy('queryAmount');
|
||||
|
||||
$data = $query->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]);
|
||||
$data = $query->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `queryAmount`')]);
|
||||
// decrypt data:
|
||||
$data->each(
|
||||
function (Model $object) {
|
||||
@ -390,9 +383,9 @@ class ReportQuery implements ReportQueryInterface
|
||||
$query->before($end)->after($start)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->groupBy('t_to.account_id')
|
||||
->orderBy('amount', 'DESC');
|
||||
->orderBy('queryAmount', 'DESC');
|
||||
|
||||
$data = $query->get(['t_to.account_id as id', 'ac_to.name as name', 'ac_to.encrypted', DB::Raw('SUM(t_to.amount) as `amount`')]);
|
||||
$data = $query->get(['t_to.account_id as id', 'ac_to.name as name', 'ac_to.encrypted', DB::Raw('SUM(t_to.amount) as `queryAmount`')]);
|
||||
|
||||
// decrypt
|
||||
$data->each(
|
||||
@ -441,10 +434,10 @@ class ReportQuery implements ReportQueryInterface
|
||||
$query->where('transaction_types.type', 'Deposit');
|
||||
}
|
||||
|
||||
$query->groupBy('t_from.account_id')->orderBy('amount');
|
||||
$query->groupBy('t_from.account_id')->orderBy('queryAmount');
|
||||
|
||||
$data = $query->get(
|
||||
['t_from.account_id as account_id', 'ac_from.name as name', 'ac_from.encrypted as encrypted', DB::Raw('SUM(t_from.amount) as `amount`')]
|
||||
['t_from.account_id as account_id', 'ac_from.name as name', 'ac_from.encrypted as encrypted', DB::Raw('SUM(t_from.amount) as `queryAmount`')]
|
||||
);
|
||||
// decrypt
|
||||
$data->each(
|
||||
@ -489,7 +482,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->get(
|
||||
['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name',
|
||||
'transactions.amount']
|
||||
'transactions.amount as queryAmount']
|
||||
);
|
||||
|
||||
}
|
||||
@ -534,7 +527,7 @@ class ReportQuery implements ReportQueryInterface
|
||||
[
|
||||
'categories.id',
|
||||
'categories.name as name',
|
||||
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`')
|
||||
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `queryAmount`')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ interface ReportQueryInterface
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
* @return float
|
||||
*/
|
||||
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end);
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
@ -8,7 +7,6 @@ use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
@ -124,18 +122,14 @@ class AccountController extends Controller
|
||||
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what);
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.' . $what);
|
||||
$size = 50;
|
||||
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
|
||||
$set = $repository->getAccounts($types, $page);
|
||||
$total = $repository->countAccounts($types);
|
||||
|
||||
$accounts = $repository->getAccounts($types);
|
||||
// last activity:
|
||||
/**
|
||||
* HERE WE ARE
|
||||
*/
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$start->subDay();
|
||||
$set->each(
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $repository) {
|
||||
$account->lastActivityDate = $repository->getLastActivity($account);
|
||||
$account->startBalance = Steam::balance($account, $start);
|
||||
@ -143,10 +137,6 @@ class AccountController extends Controller
|
||||
}
|
||||
);
|
||||
|
||||
$accounts = new LengthAwarePaginator($set, $total, $size, $page);
|
||||
$accounts->setPath(route('accounts.index', $what));
|
||||
|
||||
|
||||
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
|
||||
}
|
||||
|
||||
@ -166,7 +156,6 @@ class AccountController extends Controller
|
||||
$journals->setPath('accounts/show/' . $account->id);
|
||||
|
||||
|
||||
|
||||
return view('accounts.show', compact('account', 'what', 'subTitleIcon', 'journals', 'subTitle'));
|
||||
}
|
||||
|
||||
@ -192,7 +181,7 @@ class AccountController extends Controller
|
||||
];
|
||||
$account = $repository->store($accountData);
|
||||
|
||||
Session::flash('success', 'New account "' . $account->name . '" stored!');
|
||||
Session::flash('success', 'New account "' . $account->name . '" stored!');
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
return Redirect::route('accounts.create', $request->input('what'))->withInput();
|
||||
|
@ -45,7 +45,7 @@ class BillController extends Controller
|
||||
$expense = null;
|
||||
|
||||
// get users expense accounts:
|
||||
$accounts = $repository->getAccounts(Config::get('firefly.accountTypesByIdentifier.expense'), -1);
|
||||
$accounts = $repository->getAccounts(Config::get('firefly.accountTypesByIdentifier.expense'));
|
||||
|
||||
foreach ($matches as $match) {
|
||||
$match = strtolower($match);
|
||||
@ -173,7 +173,7 @@ class BillController extends Controller
|
||||
*/
|
||||
public function show(Bill $bill, BillRepositoryInterface $repository)
|
||||
{
|
||||
$journals = $repository->getJournals($bill);
|
||||
$journals = $repository->getJournals($bill);
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
|
||||
$hideBill = true;
|
||||
|
||||
|
@ -136,6 +136,7 @@ class CategoryController extends Controller
|
||||
$set = $repository->getJournals($category, $page);
|
||||
$count = $repository->countJournals($category);
|
||||
$journals = new LengthAwarePaginator($set, $count, 50, $page);
|
||||
$journals->setPath('categories/show/' . $category->id);
|
||||
|
||||
return view('categories.show', compact('category', 'journals', 'hideCategory'));
|
||||
}
|
||||
|
@ -1,12 +1,7 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
@ -17,11 +12,12 @@ use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
@ -46,9 +42,8 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function accountBalanceChart(Account $account, GChart $chart)
|
||||
{
|
||||
$accountName = iconv('UTF-8', 'ASCII//TRANSLIT', $account->name);
|
||||
$chart->addColumn('Day of month', 'date');
|
||||
$chart->addColumn('Balance for ' . $accountName, 'number');
|
||||
$chart->addColumn('Balance for ' . $account->name, 'number');
|
||||
$chart->addCertainty(1);
|
||||
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
@ -73,24 +68,19 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allAccountsBalanceChart(GChart $chart)
|
||||
public function allAccountsBalanceChart(GChart $chart, AccountRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Day of the month', 'date');
|
||||
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
|
||||
if ($frontPage->data == []) {
|
||||
$accounts = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
|
||||
} else {
|
||||
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
}
|
||||
$index = 1;
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$accountName = $account->name;
|
||||
$chart->addColumn('Balance for ' . $accountName, 'number');
|
||||
$chart->addColumn('Balance for ' . $account->name, 'number');
|
||||
$chart->addCertainty($index);
|
||||
$index++;
|
||||
}
|
||||
@ -108,7 +98,7 @@ class GoogleChartController extends Controller
|
||||
$current->addDay();
|
||||
}
|
||||
$chart->generate();
|
||||
//header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
@ -120,22 +110,16 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function allBudgetsAndSpending($year, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
try {
|
||||
new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
$budgets->sortBy('name');
|
||||
$budgets = $repository->getBudgets();
|
||||
$chart->addColumn('Month', 'date');
|
||||
foreach ($budgets as $budget) {
|
||||
$chart->addColumn($budget->name, 'number');
|
||||
}
|
||||
|
||||
$start = Carbon::createFromDate(intval($year), 1, 1);
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
|
||||
|
||||
while ($start <= $end) {
|
||||
$row = [clone $start];
|
||||
foreach ($budgets as $budget) {
|
||||
@ -146,7 +130,6 @@ class GoogleChartController extends Controller
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
@ -158,73 +141,44 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allBudgetsHomeChart(GChart $chart)
|
||||
public function allBudgetsHomeChart(GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
$budgets = Auth::user()->budgets()->orderBy('name', 'DESC')->get();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$budgets = $repository->getBudgets();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$allEntries = new Collection;
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
|
||||
/** @var Collection $repetitions */
|
||||
$repetitions = LimitRepetition::
|
||||
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->get(['limit_repetitions.*']);
|
||||
|
||||
// no results? search entire range for expenses and list those.
|
||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||
if ($repetitions->count() == 0) {
|
||||
$expenses = floatval($budget->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
if ($expenses > 0) {
|
||||
$chart->addRow($budget->name, 0, $expenses);
|
||||
}
|
||||
} else {
|
||||
// add with foreach:
|
||||
/** @var LimitRepetition $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
|
||||
$expenses
|
||||
=
|
||||
floatval($budget->transactionjournals()->before($repetition->enddate)->after($repetition->startdate)->lessThan(0)->sum('amount')) * -1;
|
||||
if ($expenses > 0) {
|
||||
$chart->addRow($budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses);
|
||||
}
|
||||
}
|
||||
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $start, $end);
|
||||
$allEntries->push([$budget->name, 0, $expenses]);
|
||||
continue;
|
||||
}
|
||||
/** @var LimitRepetition $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $repetition->startdate, $repetition->enddate);
|
||||
$allEntries->push([$budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses]);
|
||||
}
|
||||
}
|
||||
|
||||
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end);
|
||||
$allEntries->push(['(no budget)', 0, $noBudgetExpenses]);
|
||||
|
||||
foreach ($allEntries as $entry) {
|
||||
if ($entry[2] > 0) {
|
||||
$chart->addRow($entry[0], $entry[1], $entry[2]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$noBudgetSet = Auth::user()
|
||||
->transactionjournals()
|
||||
->whereNotIn(
|
||||
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
|
||||
$query
|
||||
->select('transaction_journals.id')
|
||||
->from('transaction_journals')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->whereNotNull('budget_transaction_journal.budget_id');
|
||||
}
|
||||
)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->lessThan(0)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->get();
|
||||
$sum = $noBudgetSet->sum('amount') * -1;
|
||||
$chart->addRow('No budget', 0, $sum);
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,34 +186,14 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allCategoriesHomeChart(GChart $chart)
|
||||
public function allCategoriesHomeChart(GChart $chart, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Category', 'string');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
// query!
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$set = TransactionJournal::
|
||||
where('transaction_journals.user_id', Auth::user()->id)
|
||||
->leftJoin(
|
||||
'transactions',
|
||||
function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->before($end)
|
||||
->where('categories.user_id', Auth::user()->id)
|
||||
->after($start)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('sum', 'DESC')
|
||||
->get(['categories.id', 'categories.encrypted', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
|
||||
$set = $repository->getCategoriesAndExpenses($start, $end);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$isEncrypted = intval($entry->encrypted) == 1 ? true : false;
|
||||
@ -275,11 +209,12 @@ class GoogleChartController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Bill $bill
|
||||
* @param GChart $chart
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function billOverview(Bill $bill, GChart $chart)
|
||||
public function billOverview(Bill $bill, GChart $chart, BillRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$chart->addColumn('Date', 'date');
|
||||
@ -288,24 +223,10 @@ class GoogleChartController extends Controller
|
||||
$chart->addColumn('Recorded bill entry', 'number');
|
||||
|
||||
// get first transaction or today for start:
|
||||
$first = $bill->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
if ($first) {
|
||||
$start = $first->date;
|
||||
} else {
|
||||
$start = new Carbon;
|
||||
}
|
||||
|
||||
$results = $bill->transactionjournals()->after($start)->get();
|
||||
$results = $repository->getJournals($bill);
|
||||
/** @var TransactionJournal $result */
|
||||
foreach ($results as $result) {
|
||||
$amount = 0;
|
||||
/** @var Transaction $tr */
|
||||
foreach ($result->transactions()->get() as $tr) {
|
||||
if (floatval($tr->amount) > 0) {
|
||||
$amount = floatval($tr->amount);
|
||||
}
|
||||
}
|
||||
$chart->addRow(clone $result->date, $bill->amount_max, $bill->amount_min, $amount);
|
||||
$chart->addRow(clone $result->date, floatval($bill->amount_max), floatval($bill->amount_min), floatval($result->amount));
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
@ -319,18 +240,21 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function billsOverview(GChart $chart, BillRepositoryInterface $repository)
|
||||
public function billsOverview(GChart $chart, BillRepositoryInterface $repository, AccountRepositoryInterface $accounts)
|
||||
{
|
||||
$chart->addColumn('Name', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
|
||||
|
||||
$paid = ['items' => [], 'amount' => 0];
|
||||
$unpaid = ['items' => [], 'amount' => 0];
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
$bills = Auth::user()->bills()->where('active', 1)->get();
|
||||
$bills = $repository->getActiveBills();
|
||||
$paid = new Collection; // journals.
|
||||
$unpaid = new Collection; // bills
|
||||
// loop paid and create single entry:
|
||||
$paidDescriptions = [];
|
||||
$paidAmount = 0;
|
||||
$unpaidDescriptions = [];
|
||||
$unpaidAmount = 0;
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
@ -338,71 +262,56 @@ class GoogleChartController extends Controller
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
|
||||
if ($count == 0) {
|
||||
$unpaid['items'][] = $bill->name . ' (' . $range['start']->format('jS M Y') . ')';
|
||||
$unpaid['amount'] += ($bill->amount_max + $bill->amount_min / 2);
|
||||
|
||||
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
|
||||
if ($journals->count() == 0) {
|
||||
$unpaid->push([$bill, $range['start']]);
|
||||
} else {
|
||||
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
|
||||
$paid['items'][] = $journal->description;
|
||||
$amount = 0;
|
||||
foreach ($journal->transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$amount = floatval($t->amount);
|
||||
}
|
||||
}
|
||||
$paid['amount'] += $amount;
|
||||
$paid = $paid->merge($journals);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
$creditCards = $accounts->getCreditCards();
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
// unpaid!
|
||||
$unpaid['amount'] += $balance * -1;
|
||||
$unpaid['items'][] = $creditCard->name . ' (expected ' . Amount::format(($balance * -1), false) . ') on the ' . $date->format('jS') . ')';
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$amount = $balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $amount);
|
||||
unset($description, $amount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// find transfer(s) TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$transactions = $creditCard->transactions()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->before($end)->after($start)->get();
|
||||
if ($transactions->count() > 0) {
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$journal = $transaction->transactionJournal;
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
$paid['amount'] += floatval($transaction->amount);
|
||||
$paid['items'][] = $creditCard->name .
|
||||
' (paid ' . Amount::format((floatval($transaction->amount)), false) .
|
||||
' on the ' . $journal->date->format('jS') . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
|
||||
$paid = $paid->merge($journals);
|
||||
}
|
||||
}
|
||||
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
|
||||
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
|
||||
|
||||
|
||||
/** @var TransactionJournal $entry */
|
||||
foreach ($paid as $entry) {
|
||||
|
||||
$paidDescriptions[] = $entry->description;
|
||||
$paidAmount += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// loop unpaid:
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
|
||||
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$unpaidDescriptions[] = $description;
|
||||
$unpaidAmount += $amount;
|
||||
unset($amount, $description);
|
||||
}
|
||||
|
||||
$chart->addRow('Unpaid: ' . join(', ', $unpaidDescriptions), $unpaidAmount);
|
||||
$chart->addRow('Paid: ' . join(', ', $paidDescriptions), $paidAmount);
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
@ -415,7 +324,7 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart)
|
||||
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$start = clone $repetition->startdate;
|
||||
$end = $repetition->enddate;
|
||||
@ -430,7 +339,7 @@ class GoogleChartController extends Controller
|
||||
/*
|
||||
* Sum of expenses on this day:
|
||||
*/
|
||||
$sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount'));
|
||||
$sum = $repository->expensesOnDay($budget, $start);
|
||||
$amount += $sum;
|
||||
$chart->addRow(clone $start, $amount);
|
||||
$start->addDay();
|
||||
@ -442,37 +351,22 @@ class GoogleChartController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param int $year
|
||||
* @param GChart $chart
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @param int $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function budgetsAndSpending(Budget $budget, $year = 0)
|
||||
public function budgetsAndSpending(Budget $budget, $year = 0, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$chart = App::make('Grumpydictator\Gchart\GChart');
|
||||
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepository');
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
if ($year == 0) {
|
||||
// grab the first budgetlimit ever:
|
||||
$firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
|
||||
if ($firstLimit) {
|
||||
$start = new Carbon($firstLimit->startdate);
|
||||
} else {
|
||||
$start = Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
// grab the last budget limit ever:
|
||||
$lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
|
||||
if ($lastLimit) {
|
||||
$end = new Carbon($lastLimit->startdate);
|
||||
} else {
|
||||
$end = Carbon::now()->endOfYear();
|
||||
}
|
||||
if ($year == 0) {
|
||||
$start = $repository->getFirstBudgetLimitDate($budget);
|
||||
$end = $repository->getLastBudgetLimitDate($budget);
|
||||
} else {
|
||||
$start = Carbon::createFromDate(intval($year), 1, 1);
|
||||
$end = clone $start;
|
||||
@ -480,19 +374,8 @@ class GoogleChartController extends Controller
|
||||
}
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentInMonth($budget, $start);
|
||||
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
|
||||
if ($repetition) {
|
||||
$budgeted = floatval($repetition->amount);
|
||||
\Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!');
|
||||
} else {
|
||||
\Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name);
|
||||
$budgeted = null;
|
||||
}
|
||||
$spent = $repository->spentInMonth($budget, $start);
|
||||
$budgeted = $repository->getLimitAmountOnDate($budget, $start);
|
||||
$chart->addRow(clone $start, $budgeted, $spent);
|
||||
$start->addMonth();
|
||||
}
|
||||
@ -510,12 +393,11 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categoryOverviewChart(Category $category, GChart $chart)
|
||||
public function categoryOverviewChart(Category $category, GChart $chart, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
// oldest transaction in category:
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
$start = $first->date;
|
||||
$start = $repository->getFirstActivityDate($category);
|
||||
|
||||
/** @var Preference $range */
|
||||
$range = Preferences::get('viewRange', '1M');
|
||||
// jump to start of week / month / year / etc (TODO).
|
||||
@ -528,13 +410,12 @@ class GoogleChartController extends Controller
|
||||
while ($start <= $end) {
|
||||
|
||||
$currentEnd = Navigation::endOfPeriod($start, $range->data);
|
||||
$spent = floatval($category->transactionjournals()->before($currentEnd)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
$spent = $repository->spentInPeriodSum($category, $start, $currentEnd);
|
||||
$chart->addRow(clone $start, $spent);
|
||||
|
||||
$start = Navigation::addPeriod($start, $range->data, 0);
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
@ -548,17 +429,15 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categoryPeriodChart(Category $category, GChart $chart)
|
||||
public function categoryPeriodChart(Category $category, GChart $chart, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
// oldest transaction in category:
|
||||
/** @var TransactionJournal $first */
|
||||
$start = clone Session::get('start');
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$chart->addColumn('Period', 'date');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
$end = Session::get('end');
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
while ($start <= $end) {
|
||||
$spent = floatval($category->transactionjournals()->onDate($start)->lessThan(0)->sum('amount')) * -1;
|
||||
$spent = $repository->spentOnDaySum($category, $start);
|
||||
$chart->addRow(clone $start, $spent);
|
||||
$start->addDay();
|
||||
}
|
||||
@ -576,13 +455,13 @@ class GoogleChartController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart)
|
||||
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Balance', 'number');
|
||||
|
||||
/** @var Collection $set */
|
||||
$set = DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
|
||||
$set = $repository->getEventSummarySet($piggyBank);
|
||||
$sum = 0;
|
||||
|
||||
foreach ($set as $entry) {
|
||||
@ -604,11 +483,7 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function yearInExp($year, GChart $chart, ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
@ -623,19 +498,9 @@ class GoogleChartController extends Controller
|
||||
while ($start < $end) {
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
// total income:
|
||||
$income = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
|
||||
$incomeSum = 0;
|
||||
foreach ($income as $entry) {
|
||||
$incomeSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// total expenses:
|
||||
$expense = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
|
||||
$expenseSum = 0;
|
||||
foreach ($expense as $entry) {
|
||||
$expenseSum += floatval($entry->amount);
|
||||
}
|
||||
// total income && total expenses:
|
||||
$incomeSum = floatval($query->incomeByPeriod($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
$expenseSum = floatval($query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
|
||||
$chart->addRow(clone $start, $incomeSum, $expenseSum);
|
||||
$start->addMonth();
|
||||
@ -656,11 +521,7 @@ class GoogleChartController extends Controller
|
||||
*/
|
||||
public function yearInExpSum($year, GChart $chart, ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
$chart->addColumn('Summary', 'string');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
@ -678,18 +539,9 @@ class GoogleChartController extends Controller
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
// total income:
|
||||
$incomeResult = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
|
||||
$incomeSum = 0;
|
||||
foreach ($incomeResult as $entry) {
|
||||
$incomeSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
$incomeSum = floatval($query->incomeByPeriod($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
// total expenses:
|
||||
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
|
||||
$expenseSum = 0;
|
||||
foreach ($expenseResult as $entry) {
|
||||
$expenseSum += floatval($entry->amount);
|
||||
}
|
||||
$expenseSum = floatval($query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
|
||||
|
||||
$income += $incomeSum;
|
||||
$expense += $expenseSum;
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
use Cache;
|
||||
use ErrorException;
|
||||
use FireflyIII\Helpers\Help\HelpInterface;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Log;
|
||||
use Response;
|
||||
use Route;
|
||||
|
||||
@ -19,73 +21,34 @@ class HelpController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show($route)
|
||||
public function show($route, HelpInterface $help)
|
||||
{
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => 'Help',
|
||||
];
|
||||
|
||||
if (!Route::has($route)) {
|
||||
\Log::error('No such route: ' . $route);
|
||||
if (!$help->hasRoute($route)) {
|
||||
Log::error('No such route: ' . $route);
|
||||
|
||||
return Response::json($content);
|
||||
}
|
||||
|
||||
if ($this->inCache($route)) {
|
||||
if ($help->inCache($route)) {
|
||||
$content = [
|
||||
'text' => Cache::get('help.' . $route . '.text'),
|
||||
'title' => Cache::get('help.' . $route . '.title'),
|
||||
'text' => $help->getFromCache('help.' . $route . '.text'),
|
||||
'title' => $help->getFromCache('help.' . $route . '.title'),
|
||||
];
|
||||
|
||||
return Response::json($content);
|
||||
}
|
||||
$content = $this->getFromGithub($route);
|
||||
$content = $help->getFromGithub($route);
|
||||
|
||||
|
||||
Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week.
|
||||
Cache::put('help.' . $route . '.title', $content['title'], 10080);
|
||||
$help->putInCache($route, $content);
|
||||
|
||||
return Response::json($content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function inCache($route)
|
||||
{
|
||||
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFromGithub($route)
|
||||
{
|
||||
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md';
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => $route,
|
||||
];
|
||||
try {
|
||||
$content['text'] = file_get_contents($uri);
|
||||
} catch (ErrorException $e) {
|
||||
\Log::error(trim($e->getMessage()));
|
||||
}
|
||||
if (strlen(trim($content['text'])) == 0) {
|
||||
$content['text'] = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
$converter = new CommonMarkConverter();
|
||||
$content['text'] = $converter->convertToHtml($content['text']);
|
||||
|
||||
return $content;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use Redirect;
|
||||
use Config;
|
||||
use Session;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class HomeController
|
||||
*
|
||||
@ -31,31 +32,45 @@ class HomeController extends Controller
|
||||
Session::put('end', $end);
|
||||
}
|
||||
|
||||
public function flush() {
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
Session::clear();
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.asset');
|
||||
$count = $repository->countAccounts($types);
|
||||
$title = 'Firefly';
|
||||
$subTitle = 'What\'s playing?';
|
||||
$mainTitleIcon = 'fa-fire';
|
||||
$transactions = [];
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
$savings = $repository->getSavingsAccounts();
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.asset');
|
||||
$count = $repository->countAccounts($types);
|
||||
$title = 'Firefly';
|
||||
$subTitle = 'What\'s playing?';
|
||||
$mainTitleIcon = 'fa-fire';
|
||||
$transactions = [];
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
$savings = $repository->getSavingsAccounts();
|
||||
$piggyBankAccounts = $repository->getPiggyBankAccounts();
|
||||
|
||||
|
||||
$savingsTotal = 0;
|
||||
foreach ($savings as $savingAccount) {
|
||||
$savingsTotal += Steam::balance($savingAccount, $end);
|
||||
}
|
||||
|
||||
// check if all books are correct.
|
||||
$sum = floatval(Auth::user()->transactions()->sum('amount'));
|
||||
$sum = $repository->sumOfEverything();
|
||||
if ($sum != 0) {
|
||||
Session::flash(
|
||||
'error', 'Your transactions are unbalanced. This means a'
|
||||
@ -71,7 +86,7 @@ class HomeController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions'));
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal','piggyBankAccounts'));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,13 +3,16 @@
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Input;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
@ -23,149 +26,124 @@ use Steam;
|
||||
class JsonController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param BillRepositoryInterface $repository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function box(BillRepositoryInterface $repository)
|
||||
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$amount = 0;
|
||||
$start = Session::get('start');
|
||||
$end = Session::get('end');
|
||||
$box = 'empty';
|
||||
switch (Input::get('box')) {
|
||||
case 'in':
|
||||
$box = Input::get('box');
|
||||
$in = Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->transactionTypes(['Deposit'])
|
||||
->where('transactions.amount', '>', 0)
|
||||
->first([DB::Raw('SUM(transactions.amount) as `amount`')]);
|
||||
if (!is_null($in)) {
|
||||
$amount = floatval($in->amount);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'out':
|
||||
$box = Input::get('box');
|
||||
$in = Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->where('transactions.amount', '>', 0)
|
||||
->first([DB::Raw('SUM(transactions.amount) as `amount`')]);
|
||||
if (!is_null($in)) {
|
||||
$amount = floatval($in->amount);
|
||||
}
|
||||
// these two functions are the same as the chart TODO
|
||||
$bills = $repository->getActiveBills();
|
||||
|
||||
break;
|
||||
case 'bills-unpaid':
|
||||
$box = 'bills-unpaid';
|
||||
$bills = Auth::user()->bills()->where('active', 1)->get();
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$amount += $repository->getJournalsInRange($bill, $range['start'], $range['end'])->sum('amount');
|
||||
}
|
||||
}
|
||||
unset($ranges, $bill, $range, $bills);
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
|
||||
if ($count == 0) {
|
||||
$amount += floatval($bill->amount_max + $bill->amount_min / 2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
if ($balance < 0) {
|
||||
// unpaid!
|
||||
$amount += $balance * -1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'bills-paid':
|
||||
$box = 'bills-paid';
|
||||
// these two functions are the same as the chart TODO
|
||||
$bills = Auth::user()->bills()->where('active', 1)->get();
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
|
||||
if ($count != 0) {
|
||||
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
|
||||
$currentAmount = 0;
|
||||
foreach ($journal->transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$currentAmount = floatval($t->amount);
|
||||
}
|
||||
}
|
||||
$amount += $currentAmount;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$transactions = $creditCard->transactions()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->before($end)->after($start)->get();
|
||||
if ($transactions->count() > 0) {
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$journal = $transaction->transactionJournal;
|
||||
if ($journal->transactionType->type == 'Transfer') {
|
||||
$amount += floatval($transaction->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$amount += $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount');
|
||||
}
|
||||
}
|
||||
|
||||
return Response::json(['box' => $box, 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
return Response::json(['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param AccountRepositoryInterface $accountRepository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxBillsUnpaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$amount = 0;
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$bills = $repository->getActiveBills();
|
||||
$unpaid = new Collection; // bills
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
|
||||
if ($journals->count() == 0) {
|
||||
$unpaid->push([$bill, $range['start']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($bill, $bills, $range, $ranges);
|
||||
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, null, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$fakeAmount = $balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
}
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$current = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$amount += $current;
|
||||
}
|
||||
|
||||
return Response::json(['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportQueryInterface $reportQuery
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxIn(ReportQueryInterface $reportQuery)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$amount = $reportQuery->incomeByPeriod($start, $end, true)->sum('queryAmount');
|
||||
|
||||
return Response::json(['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportQueryInterface $reportQuery
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxOut(ReportQueryInterface $reportQuery)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$amount = $reportQuery->journalsByExpenseAccount($start, $end, true)->sum('queryAmount');
|
||||
|
||||
return Response::json(['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,13 +151,14 @@ class JsonController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categories()
|
||||
public function categories(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$list = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
$list = $repository->getCategories();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
}
|
||||
sort($return);
|
||||
|
||||
return Response::json($return);
|
||||
}
|
||||
@ -189,9 +168,9 @@ class JsonController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function expenseAccounts()
|
||||
public function expenseAccounts(AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$list = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
|
||||
$list = $accountRepository->getAccounts(['Expense account', 'Beneficiary account']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
@ -204,9 +183,9 @@ class JsonController extends Controller
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function revenueAccounts()
|
||||
public function revenueAccounts(AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
$list = $accountRepository->getAccounts(['Revenue account']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
@ -239,13 +218,17 @@ class JsonController extends Controller
|
||||
return Response::json(['value' => $pref->data]);
|
||||
}
|
||||
|
||||
public function transactionJournals($what)
|
||||
/**
|
||||
* @param $what
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function transactionJournals($what, JournalRepositoryInterface $repository)
|
||||
{
|
||||
$descriptions = [];
|
||||
$dbType = TransactionType::whereType($what)->first();
|
||||
$journals = Auth::user()->transactionjournals()->where('transaction_type_id', $dbType->id)
|
||||
->orderBy('id', 'DESC')->take(50)
|
||||
->get();
|
||||
$dbType = $repository->getTransactionType($what);
|
||||
|
||||
$journals = $repository->getJournalsOfType($dbType);
|
||||
foreach ($journals as $j) {
|
||||
$descriptions[] = $j->description;
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
use View;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class PiggyBankController
|
||||
@ -170,7 +170,7 @@ class PiggyBankController extends Controller
|
||||
if (!isset($accounts[$account->id])) {
|
||||
$accounts[$account->id] = [
|
||||
'name' => $account->name,
|
||||
'balance' => Steam::balance($account,null,true),
|
||||
'balance' => Steam::balance($account, null, true),
|
||||
'leftForPiggyBanks' => $repository->leftOnAccount($account),
|
||||
'sumOfSaved' => $piggyBank->savedSoFar,
|
||||
'sumOfTargets' => floatval($piggyBank->targetamount),
|
||||
@ -326,6 +326,7 @@ class PiggyBankController extends Controller
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('piggy-banks.create.fromStore', true);
|
||||
|
||||
return Redirect::route('piggy-banks.create')->withInput();
|
||||
}
|
||||
|
||||
@ -360,6 +361,7 @@ class PiggyBankController extends Controller
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('piggy-banks.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('piggy-banks.edit', $piggyBank->id);
|
||||
}
|
||||
|
||||
|
@ -40,19 +40,7 @@ class RelatedController extends Controller
|
||||
$unique = array_unique($ids);
|
||||
$journals = new Collection;
|
||||
if (count($unique) > 0) {
|
||||
|
||||
$journals = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
|
||||
$journals->each(
|
||||
function (TransactionJournal $journal) {
|
||||
/** @var Transaction $t */
|
||||
foreach ($journal->transactions()->get() as $t) {
|
||||
if ($t->amount > 0) {
|
||||
$journal->amount = $t->amount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
$parent = $journal;
|
||||
|
||||
|
@ -11,7 +11,6 @@ use Preferences;
|
||||
use Session;
|
||||
use Steam;
|
||||
use View;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Class ReportController
|
||||
@ -82,7 +81,7 @@ class ReportController extends Controller
|
||||
$id = intval($budget->id);
|
||||
$data = $budget->toArray();
|
||||
$array[$id] = $data;
|
||||
if (floatval($data['amount']) != 0) {
|
||||
if (floatval($data['queryAmount']) != 0) {
|
||||
$hide = false;
|
||||
}
|
||||
}
|
||||
@ -246,7 +245,7 @@ class ReportController extends Controller
|
||||
/**
|
||||
* Start getExpenseGroupedForMonth DONE
|
||||
*/
|
||||
$set = $this->query->journalsByExpenseAccount($start, $end, $showSharedReports);
|
||||
$set = $this->query->journalsByExpenseAccount($start, $end, $showSharedReports);
|
||||
|
||||
$expenses = Steam::makeArray($set);
|
||||
$expenses = Steam::sortArray($expenses);
|
||||
|
@ -149,13 +149,7 @@ class TransactionController extends Controller
|
||||
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
|
||||
}
|
||||
|
||||
$preFilled['amount'] = 0;
|
||||
/** @var Transaction $t */
|
||||
foreach ($transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$preFilled['amount'] = floatval($t->amount);
|
||||
}
|
||||
}
|
||||
$preFilled['amount'] = $journal->amount;
|
||||
$preFilled['account_id'] = $repository->getAssetAccount($journal);
|
||||
$preFilled['expense_account'] = $transactions[0]->account->name;
|
||||
$preFilled['revenue_account'] = $transactions[1]->account->name;
|
||||
|
@ -3,17 +3,13 @@
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App;
|
||||
use Closure;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
use Session;
|
||||
use App;
|
||||
|
||||
/**
|
||||
* Class PiggyBanks
|
||||
|
@ -30,7 +30,7 @@ class BudgetFormRequest extends Request
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,encrypted';
|
||||
if (Budget::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,encrypted,'.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,encrypted,' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -30,7 +30,7 @@ class CategoryFormRequest extends Request
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,encrypted';
|
||||
if (Category::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,encrypted,'.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,encrypted,' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -3,9 +3,7 @@
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Input;
|
||||
use Navigation;
|
||||
|
||||
/**
|
||||
* Class PiggyBankFormRequest
|
||||
@ -32,7 +30,7 @@ class PiggyBankFormRequest extends Request
|
||||
$nameRule = 'required|between:1,255|uniquePiggyBankForUser';
|
||||
$targetDateRule = 'date';
|
||||
if (intval(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,255|uniquePiggyBankForUser:'.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,255|uniquePiggyBankForUser:' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
|
||||
|
@ -170,7 +170,6 @@ Route::group(
|
||||
Route::get('/bills/add/{bill}', ['uses' => 'BillController@add', 'as' => 'bills.add']);
|
||||
Route::get('/bills/delete/{bill}', ['uses' => 'BillController@delete', 'as' => 'bills.delete']);
|
||||
Route::get('/bills/show/{bill}', ['uses' => 'BillController@show', 'as' => 'bills.show']);
|
||||
|
||||
Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']);
|
||||
Route::post('/bills/update/{bill}', ['uses' => 'BillController@update', 'as' => 'bills.update']);
|
||||
Route::post('/bills/destroy/{bill}', ['uses' => 'BillController@destroy', 'as' => 'bills.destroy']);
|
||||
@ -226,7 +225,7 @@ Route::group(
|
||||
Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']);
|
||||
Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']);
|
||||
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
|
||||
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']);
|
||||
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending'])->where(['year' => '[0-9]+']);
|
||||
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
|
||||
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
|
||||
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
|
||||
@ -246,7 +245,10 @@ 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/box', ['uses' => 'JsonController@box', 'as' => 'json.box']);
|
||||
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']);
|
||||
Route::get('/json/box/bills-paid', ['uses' => 'JsonController@boxBillsPaid', 'as' => 'json.box.unpaid']);
|
||||
Route::get('/json/show-shared-reports', 'JsonController@showSharedReports');
|
||||
Route::get('/json/transaction-journals/{what}', 'JsonController@transactionJournals');
|
||||
Route::get('/json/show-shared-reports/set', 'JsonController@setSharedReports');
|
||||
|
@ -51,9 +51,11 @@ class Account extends Model
|
||||
$account = Account::create($fields);
|
||||
if (is_null($account->id)) {
|
||||
// could not create account:
|
||||
App::abort(500, 'Could not create new account with data: ' . json_encode($fields));
|
||||
App::abort(500, 'Could not create new account with data: ' . json_encode($fields).' because ' . json_encode($account->getErrors()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $account;
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Crypt;
|
||||
use App;
|
||||
/**
|
||||
* Class Category
|
||||
*
|
||||
@ -30,6 +31,39 @@ class Category extends Model
|
||||
return $this->belongsToMany('FireflyIII\Models\TransactionJournal', 'category_transaction_journal', 'category_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public static function firstOrCreateEncrypted(array $fields)
|
||||
{
|
||||
// everything but the name:
|
||||
$query = Category::orderBy('id');
|
||||
foreach ($fields as $name => $value) {
|
||||
if ($name != 'name') {
|
||||
$query->where($name, $value);
|
||||
}
|
||||
}
|
||||
$set = $query->get(['categories.*']);
|
||||
/** @var Category $category */
|
||||
foreach ($set as $category) {
|
||||
if ($category->name == $fields['name']) {
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
// create it!
|
||||
$category = Category::create($fields);
|
||||
if (is_null($category->id)) {
|
||||
// could not create account:
|
||||
App::abort(500, 'Could not create new category with data: ' . json_encode($fields));
|
||||
|
||||
}
|
||||
|
||||
return $category;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
@ -46,6 +80,7 @@ class Category extends Model
|
||||
$this->attributes['name'] = Crypt::encrypt($value);
|
||||
$this->attributes['encrypted'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Auth;
|
||||
use DB;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
@ -26,18 +28,23 @@ class LimitRepetition extends Model
|
||||
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function spentInRepetition()
|
||||
{
|
||||
$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', '>=', $this->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d'))
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('limit_repetitions.id', '=', $this->id)
|
||||
->sum('transactions.amount');
|
||||
$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', '>=', $this->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $this->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', '=', $this->id)
|
||||
->sum('transactions.amount');
|
||||
|
||||
return floatval($sum);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Class PiggyBank
|
||||
*
|
||||
@ -92,6 +93,7 @@ class PiggyBank extends Model
|
||||
$this->attributes['name'] = Crypt::encrypt($value);
|
||||
$this->attributes['encrypted'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*
|
||||
|
@ -1,9 +1,10 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Class Reminder
|
||||
*
|
||||
@ -43,6 +44,7 @@ class Reminder extends Model
|
||||
if (intval($this->encrypted) == 1) {
|
||||
return json_decode(Crypt::decrypt($value));
|
||||
}
|
||||
|
||||
return json_decode($value);
|
||||
}
|
||||
|
||||
@ -90,7 +92,7 @@ class Reminder extends Model
|
||||
public function setMetadataAttribute($value)
|
||||
{
|
||||
$this->attributes['encrypted'] = true;
|
||||
$this->attributes['metadata'] = Crypt::encrypt(json_encode($value));
|
||||
$this->attributes['metadata'] = Crypt::encrypt(json_encode($value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,10 +1,11 @@
|
||||
<?php namespace FireflyIII\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class Transaction
|
||||
*
|
||||
|
@ -55,6 +55,19 @@ class TransactionJournal extends Model
|
||||
return $this->belongsToMany('FireflyIII\Models\Category');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getAmountAttribute()
|
||||
{
|
||||
/** @var Transaction $t */
|
||||
foreach ($this->transactions as $t) {
|
||||
if ($t->amount > 0) {
|
||||
return floatval($t->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php namespace FireflyIII\Providers;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
@ -12,7 +13,8 @@ use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Log;
|
||||
use Reminder;
|
||||
use FireflyIII\Models\Reminder;
|
||||
|
||||
/**
|
||||
* Class EventServiceProvider
|
||||
*
|
||||
@ -60,14 +62,15 @@ class EventServiceProvider extends ServiceProvider
|
||||
);
|
||||
|
||||
|
||||
PiggyBank::deleting(function(PiggyBank $piggyBank) {
|
||||
$reminders = $piggyBank->reminders()->get();
|
||||
/** @var Reminder $reminder */
|
||||
foreach($reminders as $reminder) {
|
||||
$reminder->delete();
|
||||
PiggyBank::deleting(
|
||||
function (PiggyBank $piggyBank) {
|
||||
$reminders = $piggyBank->reminders()->get();
|
||||
/** @var Reminder $reminder */
|
||||
foreach ($reminders as $reminder) {
|
||||
$reminder->delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
);
|
||||
|
||||
Account::deleted(
|
||||
function (Account $account) {
|
||||
|
@ -66,6 +66,7 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search');
|
||||
|
||||
|
||||
$this->app->bind('FireflyIII\Helpers\Help\HelpInterface', 'FireflyIII\Helpers\Help\Help');
|
||||
$this->app->bind('FireflyIII\Helpers\Reminders\ReminderHelperInterface', 'FireflyIII\Helpers\Reminders\ReminderHelper');
|
||||
$this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper');
|
||||
$this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery');
|
||||
|
@ -6,6 +6,7 @@ use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
@ -53,26 +54,36 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
* @param int $page
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAccounts(array $types, $page)
|
||||
public function getAccounts(array $types)
|
||||
{
|
||||
$query = Auth::user()->accounts()->with(
|
||||
$result = Auth::user()->accounts()->with(
|
||||
['accountmeta' => function (HasMany $query) {
|
||||
$query->where('name', 'accountRole');
|
||||
}]
|
||||
)->accountTypeIn($types)->orderBy('accounts.name', 'ASC');
|
||||
)->accountTypeIn($types)->orderBy('accounts.name', 'ASC')->get(['accounts.*'])->sortBy('name');
|
||||
|
||||
if ($page == -1) {
|
||||
return $query->get(['accounts.*']);
|
||||
} else {
|
||||
$size = 50;
|
||||
$offset = ($page - 1) * $size;
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $query->take($size)->offset($offset)->get(['accounts.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCreditCards()
|
||||
{
|
||||
return Auth::user()->accounts()
|
||||
->hasMetaValue('accountRole', 'ccAsset')
|
||||
->hasMetaValue('ccType', 'monthlyFull')
|
||||
->get(
|
||||
[
|
||||
'accounts.*',
|
||||
'ccType.data as ccType',
|
||||
'accountRole.data as accountRole'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +146,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
* @param Account $account
|
||||
* @param int $page
|
||||
*
|
||||
* @return mixed
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function getJournals(Account $account, $page)
|
||||
{
|
||||
@ -177,6 +188,51 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the accounts of a user that have piggy banks connected to them.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBankAccounts()
|
||||
{
|
||||
$ids = [];
|
||||
$start = clone Session::get('start', new Carbon);
|
||||
$end = clone Session::get('end', new Carbon);
|
||||
$accountIds = DB::table('piggy_banks')->distinct()->get(['piggy_banks.account_id']);
|
||||
$accounts = new Collection;
|
||||
|
||||
foreach ($accountIds as $id) {
|
||||
$ids[] = intval($id->account_id);
|
||||
}
|
||||
|
||||
$ids = array_unique($ids);
|
||||
if (count($ids) > 0) {
|
||||
$accounts = Auth::user()->accounts()->whereIn('id', $ids)->get();
|
||||
}
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $end) {
|
||||
$account->startBalance = Steam::balance($account, $start, true);
|
||||
$account->endBalance = Steam::balance($account, $end, true);
|
||||
$account->piggyBalance = 0;
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($account->piggyBanks as $piggyBank) {
|
||||
$account->piggyBalance += $piggyBank->currentRelevantRep()->currentamount;
|
||||
}
|
||||
// sum of piggy bank amounts on this account:
|
||||
// diff between endBalance and piggyBalance.
|
||||
// then, percentage.
|
||||
$difference = $account->endBalance - $account->piggyBalance;
|
||||
$account->difference = $difference;
|
||||
$account->percentage = $difference != 0 ? round((($difference / $account->endBalance) * 100)) : 100;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
return $accounts;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get savings accounts and the balance difference in the period.
|
||||
*
|
||||
@ -219,6 +275,34 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all transfers TO this account in this range.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
return TransactionJournal::whereIn(
|
||||
'id', function ($q) use ($account, $start, $end) {
|
||||
$q->select('transaction_journals.id')
|
||||
->from('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('transaction_types.type', 'Transfer');
|
||||
|
||||
}
|
||||
)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
@ -279,6 +363,14 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function sumOfEverything()
|
||||
{
|
||||
return floatval(Auth::user()->transactions()->sum('amount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
@ -461,7 +553,6 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
protected function updateMetadata(Account $account, array $data)
|
||||
{
|
||||
$validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType'];
|
||||
$updated = false;
|
||||
|
||||
foreach ($validFields as $field) {
|
||||
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||
|
@ -7,6 +7,7 @@ use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@ -32,11 +33,10 @@ interface AccountRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
* @param int $page
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAccounts(array $types, $page);
|
||||
public function getAccounts(array $types);
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
@ -46,6 +46,30 @@ interface AccountRepositoryInterface
|
||||
*/
|
||||
public function getFirstTransaction(TransactionJournal $journal, Account $account);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCreditCards();
|
||||
|
||||
/**
|
||||
* Get the accounts of a user that have piggy banks connected to them.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBankAccounts();
|
||||
|
||||
|
||||
/**
|
||||
* Get all transfers TO this account in this range.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Preference $preference
|
||||
*
|
||||
@ -66,7 +90,7 @@ interface AccountRepositoryInterface
|
||||
* @param Account $account
|
||||
* @param string $range
|
||||
*
|
||||
* @return mixed
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function getJournals(Account $account, $page);
|
||||
|
||||
@ -77,6 +101,11 @@ interface AccountRepositoryInterface
|
||||
*/
|
||||
public function getLastActivity(Account $account);
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function sumOfEverything();
|
||||
|
||||
/**
|
||||
* Get savings accounts and the balance difference in the period.
|
||||
*
|
||||
|
@ -4,9 +4,12 @@ namespace FireflyIII\Repositories\Bill;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Navigation;
|
||||
@ -18,6 +21,31 @@ use Navigation;
|
||||
*/
|
||||
class BillRepository implements BillRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a fake bill to help the chart controller.
|
||||
*
|
||||
* @param string $description
|
||||
* @param Carbon $date
|
||||
* @param float $amount
|
||||
*
|
||||
* @return Bill
|
||||
*/
|
||||
public function createFakeBill($description, Carbon $date, $amount)
|
||||
{
|
||||
$bill = new Bill;
|
||||
$bill->name = $description;
|
||||
$bill->match = $description;
|
||||
$bill->amount_min = $amount;
|
||||
$bill->amount_max = $amount;
|
||||
$bill->date = $date;
|
||||
$bill->repeat_freq = 'monthly';
|
||||
$bill->skip = 0;
|
||||
$bill->automatch = false;
|
||||
$bill->active = false;
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
@ -28,12 +56,26 @@ class BillRepository implements BillRepositoryInterface
|
||||
return $bill->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBills()
|
||||
{
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->bills()->orderBy('name', 'ASC')->where('active', 1)->get()->sortBy('name');
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBills()
|
||||
{
|
||||
return Auth::user()->bills()->orderBy('name', 'ASC')->get();
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->bills()->orderBy('name', 'ASC')->get()->sortBy('name');
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,10 +86,30 @@ class BillRepository implements BillRepositoryInterface
|
||||
public function getJournals(Bill $bill)
|
||||
{
|
||||
return $bill->transactionjournals()->withRelevantData()
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transactions.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->get();
|
||||
->get(['transaction_journals.*', 'transactions.amount']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all journals that were recorded on this bill between these dates.
|
||||
*
|
||||
* @param Bill $bill
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournalsInRange(Bill $bill, Carbon $start, Carbon $end)
|
||||
{
|
||||
return $bill->transactionjournals()->before($end)->after($start)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,6 +315,12 @@ class BillRepository implements BillRepositoryInterface
|
||||
Log::debug('TOTAL match is true!');
|
||||
$journal->bill()->associate($bill);
|
||||
$journal->save();
|
||||
} else {
|
||||
if ((!$wordMatch || !$amountMatch) && $bill->id == $journal->bill_id) {
|
||||
// if no match, but bill used to match, remove it:
|
||||
$journal->bill_id = null;
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,17 @@ use Illuminate\Support\Collection;
|
||||
interface BillRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a fake bill to help the chart controller.
|
||||
*
|
||||
* @param string $description
|
||||
* @param Carbon $date
|
||||
* @param float $amount
|
||||
*
|
||||
* @return Bill
|
||||
*/
|
||||
public function createFakeBill($description, Carbon $date, $amount);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
@ -22,6 +33,11 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
public function destroy(Bill $bill);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBills();
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@ -32,14 +48,25 @@ interface BillRepositoryInterface
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPossiblyRelatedJournals(Bill $bill);
|
||||
public function getJournals(Bill $bill);
|
||||
|
||||
/**
|
||||
* Get all journals that were recorded on this bill between these dates.
|
||||
*
|
||||
* @param Bill $bill
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournalsInRange(Bill $bill, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournals(Bill $bill);
|
||||
public function getPossiblyRelatedJournals(Bill $bill);
|
||||
|
||||
/**
|
||||
* Every bill repeats itself weekly, monthly or yearly (or whatever). This method takes a date-range (usually the view-range of Firefly itself)
|
||||
@ -61,6 +88,7 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
public function lastFoundMatch(Bill $bill);
|
||||
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
|
@ -7,6 +7,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@ -55,12 +56,65 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function expensesOnDay(Budget $budget, Carbon $date)
|
||||
{
|
||||
return floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($date)->sum('amount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBudgets()
|
||||
{
|
||||
return Auth::user()->budgets()->where('active', 1)->get();
|
||||
$budgets = Auth::user()->budgets()->where('active', 1)->get();
|
||||
$budgets->sortBy('name');
|
||||
|
||||
return $budgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimitRepetitions(Budget $budget, Carbon $start, Carbon $end)
|
||||
{
|
||||
/** @var Collection $repetitions */
|
||||
return LimitRepetition::
|
||||
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->get(['limit_repetitions.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimits(Budget $budget)
|
||||
{
|
||||
return $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgets()
|
||||
{
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
$budgets->sortBy('name');
|
||||
|
||||
return $budgets;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,12 +128,27 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getFirstBudgetLimitDate(Budget $budget)
|
||||
{
|
||||
$limit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
|
||||
if ($limit) {
|
||||
return $limit->startdate;
|
||||
}
|
||||
|
||||
return Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInactiveBudgets()
|
||||
{
|
||||
return Auth::user()->budgets()->where('active', 1)->get();
|
||||
return Auth::user()->budgets()->where('active', 0)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,6 +184,41 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return new LengthAwarePaginator($set, $count, $take, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getLastBudgetLimitDate(Budget $budget)
|
||||
{
|
||||
$limit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
|
||||
if ($limit) {
|
||||
return $limit->startdate;
|
||||
}
|
||||
|
||||
return Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float|null
|
||||
*/
|
||||
public function getLimitAmountOnDate(Budget $budget, Carbon $date)
|
||||
{
|
||||
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', $date->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
|
||||
if ($repetition) {
|
||||
return floatval($repetition->amount);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@ -135,6 +239,36 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWithoutBudgetSum(Carbon $start, Carbon $end)
|
||||
{
|
||||
$noBudgetSet = Auth::user()
|
||||
->transactionjournals()
|
||||
->whereNotIn(
|
||||
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
|
||||
$query
|
||||
->select('transaction_journals.id')
|
||||
->from('transaction_journals')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
|
||||
->whereNotNull('budget_transaction_journal.budget_id');
|
||||
}
|
||||
)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->lessThan(0)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->get();
|
||||
|
||||
return floatval($noBudgetSet->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
@ -169,6 +303,18 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return $newBudget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function sumBudgetExpensesInPeriod(Budget $budget, $start, $end)
|
||||
{
|
||||
return floatval($budget->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
@ -224,14 +370,4 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetLimits(Budget $budget)
|
||||
{
|
||||
return $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,11 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface BudgetRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanupBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
@ -21,36 +26,27 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function destroy(Budget $budget);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBudgets();
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInactiveBudgets();
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanupBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInMonth(Budget $budget, Carbon $date);
|
||||
public function expensesOnDay(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getWithoutBudget(Carbon $start, Carbon $end);
|
||||
public function getBudgetLimitRepetitions(Budget $budget, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
@ -59,6 +55,11 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function getBudgetLimits(Budget $budget);
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgets();
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
@ -69,27 +70,15 @@ interface BudgetRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
* @param $amount
|
||||
*
|
||||
* @return mixed
|
||||
* @return Carbon
|
||||
*/
|
||||
public function updateLimitAmount(Budget $budget, Carbon $date, $amount);
|
||||
public function getFirstBudgetLimitDate(Budget $budget);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
* @return Collection
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
*/
|
||||
public function update(Budget $budget, array $data);
|
||||
public function getInactiveBudgets();
|
||||
|
||||
/**
|
||||
* Returns all the transaction journals for a limit, possibly limited by a limit repetition.
|
||||
@ -102,4 +91,76 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getLastBudgetLimitDate(Budget $budget);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getLimitAmountOnDate(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getWithoutBudget(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWithoutBudgetSum(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInMonth(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function sumBudgetExpensesInPeriod(Budget $budget, $start, $end);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
*/
|
||||
public function update(Budget $budget, array $data);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
* @param $amount
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateLimitAmount(Budget $budget, Carbon $date, $amount);
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,10 @@ namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@ -43,7 +46,62 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
*/
|
||||
public function getCategories()
|
||||
{
|
||||
return Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
/** @var Collection $set */
|
||||
$set = Auth::user()->categories()->orderBy('name', 'ASC')->get();
|
||||
$set->sortBy(
|
||||
function (Category $category) {
|
||||
return $category->name;
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategoriesAndExpenses($start, $end)
|
||||
{
|
||||
return TransactionJournal::
|
||||
where('transaction_journals.user_id', Auth::user()->id)
|
||||
->leftJoin(
|
||||
'transactions',
|
||||
function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->before($end)
|
||||
->where('categories.user_id', Auth::user()->id)
|
||||
->after($start)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('sum', 'DESC')
|
||||
->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getFirstActivityDate(Category $category)
|
||||
{
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
if ($first) {
|
||||
return $first->date;
|
||||
}
|
||||
|
||||
return new Carbon;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,6 +163,29 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInPeriodSum(Category $category, Carbon $start, Carbon $end)
|
||||
{
|
||||
return floatval($category->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentOnDaySum(Category $category, Carbon $date)
|
||||
{
|
||||
return floatval($category->transactionjournals()->onDate($date)->lessThan(0)->sum('amount')) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
|
@ -32,6 +32,21 @@ interface CategoryRepositoryInterface
|
||||
*/
|
||||
public function getCategories();
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategoriesAndExpenses($start, $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getFirstActivityDate(Category $category);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param int $page
|
||||
@ -55,6 +70,23 @@ interface CategoryRepositoryInterface
|
||||
*/
|
||||
public function getWithoutCategory(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInPeriodSum(Category $category, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentOnDaySum(Category $category, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
|
@ -81,4 +81,4 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,4 +49,4 @@ interface CurrencyRepositoryInterface
|
||||
*/
|
||||
public function update(TransactionCurrency $currency, array $data);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,26 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
return $journal->transactions()->first()->account_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionType $dbType
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournalsOfType(TransactionType $dbType)
|
||||
{
|
||||
return Auth::user()->transactionjournals()->where('transaction_type_id', $dbType->id)->orderBy('id', 'DESC')->take(50)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return TransactionType
|
||||
*/
|
||||
public function getTransactionType($type)
|
||||
{
|
||||
return TransactionType::whereType($type)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param TransactionJournal $journal
|
||||
@ -140,7 +160,7 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
// store or get category
|
||||
if (strlen($data['category']) > 0) {
|
||||
$category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$category = Category::firstOrCreateEncrypted(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$journal->categories()->save($category);
|
||||
}
|
||||
|
||||
@ -193,7 +213,7 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
// unlink all categories, recreate them:
|
||||
$journal->categories()->detach();
|
||||
if (strlen($data['category']) > 0) {
|
||||
$category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$category = Category::firstOrCreateEncrypted(['name' => $data['category'], 'user_id' => $data['user']]);
|
||||
$journal->categories()->save($category);
|
||||
}
|
||||
|
||||
@ -289,5 +309,4 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
|
||||
return [$from, $to];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
namespace FireflyIII\Repositories\Journal;
|
||||
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@ -13,6 +14,13 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface JournalRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
*
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
public function first();
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the account_id, which is the asset account that paid for the transaction.
|
||||
@ -23,6 +31,13 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function getAssetAccount(TransactionJournal $journal);
|
||||
|
||||
/**
|
||||
* @param TransactionType $dbType
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getJournalsOfType(TransactionType $dbType);
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param TransactionJournal $journal
|
||||
@ -31,6 +46,13 @@ interface JournalRepositoryInterface
|
||||
*/
|
||||
public function searchRelated($query, TransactionJournal $journal);
|
||||
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*
|
||||
* @return TransactionType
|
||||
*/
|
||||
public function getTransactionType($type);
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@ -45,10 +67,4 @@ interface JournalRepositoryInterface
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(TransactionJournal $journal, array $data);
|
||||
|
||||
/**
|
||||
* Get users first transaction journal
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
public function first();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use Navigation;
|
||||
class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
@ -86,6 +87,18 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return $part;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEventSummarySet(PiggyBank $piggyBank)
|
||||
{
|
||||
return DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set all piggy banks to order 0.
|
||||
*
|
||||
|
@ -14,7 +14,6 @@ use Illuminate\Support\Collection;
|
||||
interface PiggyBankRepositoryInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
@ -35,6 +34,13 @@ interface PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function createPiggyBankPart(array $data);
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEventSummarySet(PiggyBank $piggyBank);
|
||||
|
||||
/**
|
||||
* Set all piggy banks to order 0.
|
||||
*
|
||||
|
@ -67,8 +67,8 @@ class Steam
|
||||
public function limitArray(array $array, $limit = 10)
|
||||
{
|
||||
$others = [
|
||||
'name' => 'Others',
|
||||
'amount' => 0
|
||||
'name' => 'Others',
|
||||
'queryAmount' => 0
|
||||
];
|
||||
$return = [];
|
||||
$count = 0;
|
||||
@ -76,7 +76,7 @@ class Steam
|
||||
if ($count < ($limit - 1)) {
|
||||
$return[$id] = $entry;
|
||||
} else {
|
||||
$others['amount'] += $entry['amount'];
|
||||
$others['queryAmount'] += $entry['queryAmount'];
|
||||
}
|
||||
|
||||
$count++;
|
||||
@ -103,14 +103,16 @@ class Steam
|
||||
$id = intval($entry->id);
|
||||
if (isset($array[$id])) {
|
||||
$array[$id]['amount'] += floatval($entry->amount);
|
||||
$array[$id]['queryAmount'] += floatval($entry->queryAmount);
|
||||
$array[$id]['spent'] += floatval($entry->spent);
|
||||
$array[$id]['encrypted'] = intval($entry->encrypted);
|
||||
} else {
|
||||
$array[$id] = [
|
||||
'amount' => floatval($entry->amount),
|
||||
'spent' => floatval($entry->spent),
|
||||
'encrypted' => intval($entry->encrypted),
|
||||
'name' => $entry->name
|
||||
'amount' => floatval($entry->amount),
|
||||
'queryAmount' => floatval($entry->queryAmount),
|
||||
'spent' => floatval($entry->spent),
|
||||
'encrypted' => intval($entry->encrypted),
|
||||
'name' => $entry->name
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -131,7 +133,7 @@ class Steam
|
||||
foreach ($two as $id => $value) {
|
||||
// $otherId also exists in $one:
|
||||
if (isset($one[$id])) {
|
||||
$one[$id]['amount'] += $value['amount'];
|
||||
$one[$id]['queryAmount'] += $value['queryAmount'];
|
||||
$one[$id]['spent'] += $value['spent'];
|
||||
} else {
|
||||
$one[$id] = $value;
|
||||
@ -170,11 +172,11 @@ class Steam
|
||||
{
|
||||
uasort(
|
||||
$array, function ($left, $right) {
|
||||
if ($left['amount'] == $right['amount']) {
|
||||
if ($left['queryAmount'] == $right['queryAmount']) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($left['amount'] < $right['amount']) ? 1 : -1;
|
||||
return ($left['queryAmount'] < $right['queryAmount']) ? 1 : -1;
|
||||
}
|
||||
);
|
||||
|
||||
@ -193,11 +195,11 @@ class Steam
|
||||
{
|
||||
uasort(
|
||||
$array, function ($left, $right) {
|
||||
if ($left['amount'] == $right['amount']) {
|
||||
if ($left['queryAmount'] == $right['queryAmount']) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($left['amount'] < $right['amount']) ? -1 : 1;
|
||||
return ($left['queryAmount'] < $right['queryAmount']) ? -1 : 1;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -223,10 +223,10 @@ class FireflyValidator extends Validator
|
||||
}
|
||||
$set = $query->get(['piggy_banks.*']);
|
||||
|
||||
foreach($set as $entry) {
|
||||
foreach ($set as $entry) {
|
||||
$isEncrypted = intval($entry->encrypted) == 1 ? true : false;
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->name) : $entry->name;
|
||||
if($checkValue == $value) {
|
||||
$checkValue = $isEncrypted ? Crypt::decrypt($entry->name) : $entry->name;
|
||||
if ($checkValue == $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
109
composer.lock
generated
109
composer.lock
generated
@ -677,16 +677,16 @@
|
||||
},
|
||||
{
|
||||
"name": "grumpydictator/gchart",
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JC5/gchart.git",
|
||||
"reference": "24d06101cfda7ff336ecb10f7f0cb0d6004cb83c"
|
||||
"reference": "920a0494a0697472bf81c0111b6825c516099e59"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/JC5/gchart/zipball/24d06101cfda7ff336ecb10f7f0cb0d6004cb83c",
|
||||
"reference": "24d06101cfda7ff336ecb10f7f0cb0d6004cb83c",
|
||||
"url": "https://api.github.com/repos/JC5/gchart/zipball/920a0494a0697472bf81c0111b6825c516099e59",
|
||||
"reference": "920a0494a0697472bf81c0111b6825c516099e59",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -709,7 +709,7 @@
|
||||
}
|
||||
],
|
||||
"description": "GChart is a small package that allows you to easily generate data for the Google Charts API.",
|
||||
"time": "2015-02-20 20:07:26"
|
||||
"time": "2015-04-05 19:17:17"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/html",
|
||||
@ -945,16 +945,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.0.26",
|
||||
"version": "v5.0.27",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "8e53c33e144f94032cc6ecbfee0be2a96ed63be0"
|
||||
"reference": "4d6330118a295086ce9ff8eed2200d5b67f17688"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8e53c33e144f94032cc6ecbfee0be2a96ed63be0",
|
||||
"reference": "8e53c33e144f94032cc6ecbfee0be2a96ed63be0",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/4d6330118a295086ce9ff8eed2200d5b67f17688",
|
||||
"reference": "4d6330118a295086ce9ff8eed2200d5b67f17688",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1067,7 +1067,7 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2015-04-03 02:58:05"
|
||||
"time": "2015-04-04 01:34:57"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
@ -1377,16 +1377,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v1.2.1",
|
||||
"version": "v1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "dba7524b3724f25b947cd26a580787c55c8a6f9b"
|
||||
"reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dba7524b3724f25b947cd26a580787c55c8a6f9b",
|
||||
"reference": "dba7524b3724f25b947cd26a580787c55c8a6f9b",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08f97eb4efa029e2fafb6d8c98b71731bf0cf621",
|
||||
"reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1418,7 +1418,7 @@
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"time": "2015-03-24 19:10:28"
|
||||
"time": "2015-04-03 14:33:59"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
@ -3225,31 +3225,33 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.3.4",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
|
||||
"reference": "a923bb15680d0089e2316f7a4af8f437046e96bb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
|
||||
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb",
|
||||
"reference": "a923bb15680d0089e2316f7a4af8f437046e96bb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"File/"
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
@ -3266,7 +3268,7 @@
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2013-10-10 15:34:57"
|
||||
"time": "2015-04-02 05:19:05"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
@ -3407,16 +3409,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.5.1",
|
||||
"version": "4.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "d6429b0995b24a2d9dfe5587ee3a7071c1161af4"
|
||||
"reference": "08b2aacdd8433abbba468f995d6d64b76a7a62ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d6429b0995b24a2d9dfe5587ee3a7071c1161af4",
|
||||
"reference": "d6429b0995b24a2d9dfe5587ee3a7071c1161af4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/08b2aacdd8433abbba468f995d6d64b76a7a62ec",
|
||||
"reference": "08b2aacdd8433abbba468f995d6d64b76a7a62ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3428,17 +3430,17 @@
|
||||
"php": ">=5.3.3",
|
||||
"phpspec/prophecy": "~1.3,>=1.3.1",
|
||||
"phpunit/php-code-coverage": "~2.0,>=2.0.11",
|
||||
"phpunit/php-file-iterator": "~1.3.2",
|
||||
"phpunit/php-file-iterator": "~1.4",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "~1.0.2",
|
||||
"phpunit/php-timer": "~1.0",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/diff": "~1.1",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "~1.2",
|
||||
"sebastian/exporter": "~1.2",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/version": "~1.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
"symfony/yaml": "~2.1|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"phpunit/php-invoker": "~1.1"
|
||||
@ -3449,12 +3451,15 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.5.x-dev"
|
||||
"dev-master": "4.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
],
|
||||
"files": [
|
||||
"src/Framework/Assert/Functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@ -3475,7 +3480,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-03-29 09:24:05"
|
||||
"time": "2015-04-03 13:46:59"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@ -3666,16 +3671,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7"
|
||||
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7",
|
||||
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3",
|
||||
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3687,7 +3692,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3714,32 +3719,32 @@
|
||||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"time": "2014-08-15 10:29:00"
|
||||
"time": "2015-02-22 15:13:53"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7"
|
||||
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7",
|
||||
"reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
|
||||
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.3"
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3764,7 +3769,7 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2014-10-25 08:00:45"
|
||||
"time": "2015-01-01 10:01:08"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@ -3938,16 +3943,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "a77d9123f8e809db3fbdea15038c27a95da4058b"
|
||||
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b",
|
||||
"reference": "a77d9123f8e809db3fbdea15038c27a95da4058b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
|
||||
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -3969,7 +3974,7 @@
|
||||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"time": "2014-12-15 14:25:24"
|
||||
"time": "2015-02-24 06:35:25"
|
||||
},
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
|
@ -136,8 +136,6 @@ return [
|
||||
'Illuminate\Validation\ValidationServiceProvider',
|
||||
'Illuminate\View\ViewServiceProvider',
|
||||
'Illuminate\Html\HtmlServiceProvider',
|
||||
'Barryvdh\Debugbar\ServiceProvider',
|
||||
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
|
||||
/*
|
||||
|
@ -426,7 +426,6 @@ class ChangesForV321 extends Migration
|
||||
|
||||
public function moveComponentIdToBudgetId()
|
||||
{
|
||||
//Log::debug('Now in moveComponentIdToBudgetId()');
|
||||
BudgetLimit::get()->each(
|
||||
function (BudgetLimit $bl) {
|
||||
Log::debug('Now at budgetLimit #' . $bl->id . ' with component_id: ' . $bl->component_id);
|
||||
@ -447,7 +446,6 @@ class ChangesForV321 extends Migration
|
||||
}
|
||||
}
|
||||
);
|
||||
//Log::debug('Done with moveComponentIdToBudgetId()');
|
||||
|
||||
}
|
||||
|
||||
|
100
public/css/bootstrap-sortable.css
vendored
Normal file
100
public/css/bootstrap-sortable.css
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
table.sortable span.sign {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
color: #bfbfc1;
|
||||
}
|
||||
|
||||
table.sortable th:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
color: #bfbfc1;
|
||||
}
|
||||
|
||||
table.sortable th.arrow:after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
table.sortable span.arrow, span.reversed, th.arrow.down:after, th.reversedarrow.down:after, th.arrow.up:after, th.reversedarrow.up:after {
|
||||
border-style: solid;
|
||||
border-width: 5px;
|
||||
font-size: 0;
|
||||
border-color: #ccc transparent transparent transparent;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
table.sortable span.arrow.up, th.arrow.up:after {
|
||||
border-color: transparent transparent #ccc transparent;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
table.sortable span.reversed, th.reversedarrow.down:after {
|
||||
border-color: transparent transparent #ccc transparent;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
table.sortable span.reversed.up, th.reversedarrow.up:after {
|
||||
border-color: #ccc transparent transparent transparent;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
table.sortable span.az:before, th.az.down:after {
|
||||
content: "a .. z";
|
||||
}
|
||||
|
||||
table.sortable span.az.up:before, th.az.up:after {
|
||||
content: "z .. a";
|
||||
}
|
||||
|
||||
table.sortable th.az.nosort:after, th.AZ.nosort:after, th._19.nosort:after, th.month.nosort:after {
|
||||
content: "..";
|
||||
}
|
||||
|
||||
table.sortable span.AZ:before, th.AZ.down:after {
|
||||
content: "A .. Z";
|
||||
}
|
||||
|
||||
table.sortable span.AZ.up:before, th.AZ.up:after {
|
||||
content: "Z .. A";
|
||||
}
|
||||
|
||||
table.sortable span._19:before, th._19.down:after {
|
||||
content: "1 .. 9";
|
||||
}
|
||||
|
||||
table.sortable span._19.up:before, th._19.up:after {
|
||||
content: "9 .. 1";
|
||||
}
|
||||
|
||||
table.sortable span.month:before, th.month.down:after {
|
||||
content: "jan .. dec";
|
||||
}
|
||||
|
||||
table.sortable span.month.up:before, th.month.up:after {
|
||||
content: "dec .. jan";
|
||||
}
|
||||
|
||||
table.sortable thead th:not([data-defaultsort=disabled]) {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
table.sortable thead th:hover:not([data-defaultsort=disabled]) {
|
||||
background: #efefef;
|
||||
}
|
||||
|
||||
table.sortable thead th div.mozilla {
|
||||
position: relative;
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
#daterange {cursor:pointer;}
|
||||
.google-chart-error {height:30px;background:url('/images/error.png') no-repeat center center;}
|
||||
.handle {cursor:move;}
|
||||
.handle {cursor:move;}
|
||||
|
||||
.ui-sortable-placeholder {
|
||||
display: inline-block;
|
||||
height: 1px;
|
||||
}
|
209
public/js/bootstrap-sortable.js
vendored
Normal file
209
public/js/bootstrap-sortable.js
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* TinySort is a small script that sorts HTML elements. It sorts by text- or attribute value, or by that of one of it's children.
|
||||
* @summary A nodeElement sorting script.
|
||||
* @version 2.2.0
|
||||
* @license MIT/GPL
|
||||
* @author Ron Valstar <ron@ronvalstar.nl>
|
||||
* @copyright Ron Valstar <ron@ronvalstar.nl>
|
||||
* @namespace tinysort
|
||||
*/
|
||||
!function (a, b) { "use strict"; function c() { return b } "function" == typeof define && define.amd ? define("tinysort", c) : a.tinysort = b }(this, function () { "use strict"; function a(a, f) { function j() { 0 === arguments.length ? s({}) : d(arguments, function (a) { s(c(a) ? { selector: a } : a) }), p = D.length } function s(a) { var b = !!a.selector, c = b && ":" === a.selector[0], d = e(a || {}, r); D.push(e({ hasSelector: b, hasAttr: !(d.attr === i || "" === d.attr), hasData: d.data !== i, hasFilter: c, sortReturnNumber: "asc" === d.order ? 1 : -1 }, d)) } function t() { d(a, function (a, b) { y ? y !== a.parentNode && (E = !1) : y = a.parentNode; var c = D[0], d = c.hasFilter, e = c.selector, f = !e || d && a.matchesSelector(e) || e && a.querySelector(e), g = f ? B : C, h = { elm: a, pos: b, posn: g.length }; A.push(h), g.push(h) }), x = B.slice(0) } function u() { B.sort(v) } function v(a, e) { var f = 0; for (0 !== q && (q = 0) ; 0 === f && p > q;) { var i = D[q], j = i.ignoreDashes ? n : m; if (d(o, function (a) { var b = a.prepare; b && b(i) }), i.sortFunction) f = i.sortFunction(a, e); else if ("rand" == i.order) f = Math.random() < .5 ? 1 : -1; else { var k = h, r = b(a, i), s = b(e, i), t = "" === r || r === g, u = "" === s || s === g; if (r === s) f = 0; else if (i.emptyEnd && (t || u)) f = t && u ? 0 : t ? 1 : -1; else { if (!i.forceStrings) { var v = c(r) ? r && r.match(j) : h, w = c(s) ? s && s.match(j) : h; if (v && w) { var x = r.substr(0, r.length - v[0].length), y = s.substr(0, s.length - w[0].length); x == y && (k = !h, r = l(v[0]), s = l(w[0])) } } f = r === g || s === g ? 0 : s > r ? -1 : r > s ? 1 : 0 } } d(o, function (a) { var b = a.sort; b && (f = b(i, k, r, s, f)) }), f *= i.sortReturnNumber, 0 === f && q++ } return 0 === f && (f = a.pos > e.pos ? 1 : -1), f } function w() { var a = B.length === A.length; E && a ? F ? B.forEach(function (a, b) { a.elm.style.order = b }) : (B.forEach(function (a) { z.appendChild(a.elm) }), y.appendChild(z)) : (B.forEach(function (a) { var b = a.elm, c = k.createElement("div"); a.ghost = c, b.parentNode.insertBefore(c, b) }), B.forEach(function (a, b) { var c = x[b].ghost; c.parentNode.insertBefore(a.elm, c), c.parentNode.removeChild(c) })) } c(a) && (a = k.querySelectorAll(a)), 0 === a.length && console.warn("No elements to sort"); var x, y, z = k.createDocumentFragment(), A = [], B = [], C = [], D = [], E = !0, F = a.length && (f === g || f.useFlex !== !1) && -1 !== getComputedStyle(a[0].parentNode, null).display.indexOf("flex"); return j.apply(i, Array.prototype.slice.call(arguments, 1)), t(), u(), w(), B.map(function (a) { return a.elm }) } function b(a, b) { var d, e = a.elm; return b.selector && (b.hasFilter ? e.matchesSelector(b.selector) || (e = i) : e = e.querySelector(b.selector)), b.hasAttr ? d = e.getAttribute(b.attr) : b.useVal ? d = e.value || e.getAttribute("value") : b.hasData ? d = e.getAttribute("data-" + b.data) : e && (d = e.textContent), c(d) && (b.cases || (d = d.toLowerCase()), d = d.replace(/\s+/g, " ")), d } function c(a) { return "string" == typeof a } function d(a, b) { for (var c, d = a.length, e = d; e--;) c = d - e - 1, b(a[c], c) } function e(a, b, c) { for (var d in b) (c || a[d] === g) && (a[d] = b[d]); return a } function f(a, b, c) { o.push({ prepare: a, sort: b, sortBy: c }) } var g, h = !1, i = null, j = window, k = j.document, l = parseFloat, m = /(-?\d+\.?\d*)\s*$/g, n = /(\d+\.?\d*)\s*$/g, o = [], p = 0, q = 0, r = { selector: i, order: "asc", attr: i, data: i, useVal: h, place: "start", returns: h, cases: h, forceStrings: h, ignoreDashes: h, sortFunction: i, useFlex: h, emptyEnd: h }; return j.Element && function (a) { a.matchesSelector = a.matchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector || a.webkitMatchesSelector || function (a) { for (var b = this, c = (b.parentNode || b.document).querySelectorAll(a), d = -1; c[++d] && c[d] != b;); return !!c[d] } }(Element.prototype), e(f, { loop: d }), e(a, { plugin: f, defaults: r }) }());
|
||||
|
||||
(function ($) {
|
||||
|
||||
var $document = $(document),
|
||||
signClass,
|
||||
sortEngine;
|
||||
|
||||
$.bootstrapSortable = function (applyLast, sign, customSort) {
|
||||
|
||||
// Check if moment.js is available
|
||||
var momentJsAvailable = (typeof moment !== 'undefined');
|
||||
|
||||
// Set class based on sign parameter
|
||||
signClass = !sign ? "arrow" : sign;
|
||||
|
||||
// Set sorting algorithm
|
||||
if (customSort == 'default')
|
||||
customSort = defaultSortEngine;
|
||||
sortEngine = customSort || sortEngine || defaultSortEngine;
|
||||
|
||||
// Set attributes needed for sorting
|
||||
$('table.sortable').each(function () {
|
||||
var $this = $(this);
|
||||
applyLast = (applyLast === true);
|
||||
$this.find('span.sign').remove();
|
||||
|
||||
// Add placeholder cells for colspans
|
||||
$this.find('thead [colspan]').each(function () {
|
||||
var colspan = parseFloat($(this).attr('colspan'));
|
||||
for (var i = 1; i < colspan; i++) {
|
||||
$(this).after('<th class="colspan-compensate">');
|
||||
}
|
||||
});
|
||||
|
||||
// Add placeholder cells for rowspans
|
||||
$this.find('thead [rowspan]').each(function () {
|
||||
var $cell = $(this);
|
||||
var rowspan = parseFloat($cell.attr('rowspan'));
|
||||
for (var i = 1; i < rowspan; i++) {
|
||||
var parentRow = $cell.parent('tr');
|
||||
var nextRow = parentRow.next('tr');
|
||||
var index = parentRow.children().index($cell);
|
||||
nextRow.children().eq(index).before('<th class="rowspan-compensate">');
|
||||
}
|
||||
});
|
||||
|
||||
// Set indexes to header cells
|
||||
$this.find('thead tr').each(function (rowIndex) {
|
||||
$(this).find('th').each(function (columnIndex) {
|
||||
var $this = $(this);
|
||||
$this.addClass('nosort').removeClass('up down');
|
||||
$this.attr('data-sortcolumn', columnIndex);
|
||||
$this.attr('data-sortkey', columnIndex + '-' + rowIndex);
|
||||
});
|
||||
});
|
||||
|
||||
// Cleanup placeholder cells
|
||||
$this.find('thead .rowspan-compensate, .colspan-compensate').remove();
|
||||
|
||||
// Initialize sorting values
|
||||
$this.find('td').each(function () {
|
||||
var $this = $(this);
|
||||
if ($this.attr('data-dateformat') !== undefined && momentJsAvailable) {
|
||||
$this.attr('data-value', moment($this.text(), $this.attr('data-dateformat')).format('YYYY/MM/DD/HH/mm/ss'));
|
||||
}
|
||||
else {
|
||||
$this.attr('data-value') === undefined && $this.attr('data-value', $this.text());
|
||||
}
|
||||
});
|
||||
|
||||
var context = lookupSortContext($this),
|
||||
bsSort = context.bsSort;
|
||||
|
||||
$this.find('thead th[data-defaultsort!="disabled"]').each(function (index) {
|
||||
var $this = $(this);
|
||||
var $sortTable = $this.closest('table.sortable');
|
||||
$this.data('sortTable', $sortTable);
|
||||
var sortKey = $this.attr('data-sortkey');
|
||||
var thisLastSort = applyLast ? context.lastSort : -1;
|
||||
bsSort[sortKey] = applyLast ? bsSort[sortKey] : $this.attr('data-defaultsort');
|
||||
if (bsSort[sortKey] !== undefined && (applyLast === (sortKey === thisLastSort))) {
|
||||
bsSort[sortKey] = bsSort[sortKey] === 'asc' ? 'desc' : 'asc';
|
||||
doSort($this, $sortTable);
|
||||
}
|
||||
});
|
||||
$this.trigger('sorted');
|
||||
});
|
||||
};
|
||||
|
||||
// Add click event to table header
|
||||
$document.on('click', 'table.sortable thead th[data-defaultsort!="disabled"]', function (e) {
|
||||
var $this = $(this), $table = $this.data('sortTable') || $this.closest('table.sortable');
|
||||
$table.trigger('before-sort');
|
||||
doSort($this, $table);
|
||||
$table.trigger('sorted');
|
||||
});
|
||||
|
||||
// Look up sorting data appropriate for the specified table (jQuery element).
|
||||
// This allows multiple tables on one page without collisions.
|
||||
function lookupSortContext($table) {
|
||||
var context = $table.data("bootstrap-sortable-context");
|
||||
if (context === undefined) {
|
||||
context = { bsSort: [], lastSort: undefined };
|
||||
$table.find('thead th[data-defaultsort!="disabled"]').each(function (index) {
|
||||
var $this = $(this);
|
||||
var sortKey = $this.attr('data-sortkey');
|
||||
context.bsSort[sortKey] = $this.attr('data-defaultsort');
|
||||
if (context.bsSort[sortKey] !== undefined) {
|
||||
context.lastSort = sortKey;
|
||||
}
|
||||
});
|
||||
$table.data("bootstrap-sortable-context", context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
function defaultSortEngine(rows, sortingParams) {
|
||||
tinysort(rows, sortingParams);
|
||||
}
|
||||
|
||||
// Sorting mechanism separated
|
||||
function doSort($this, $table) {
|
||||
var sortColumn = parseFloat($this.attr('data-sortcolumn')),
|
||||
context = lookupSortContext($table),
|
||||
bsSort = context.bsSort;
|
||||
|
||||
var colspan = $this.attr('colspan');
|
||||
if (colspan) {
|
||||
var mainSort = parseFloat($this.data('mainsort')) || 0;
|
||||
var rowIndex = parseFloat($this.data('sortkey').split('-').pop());
|
||||
|
||||
// If there is one more row in header, delve deeper
|
||||
if ($table.find('thead tr').length - 1 > rowIndex) {
|
||||
doSort($table.find('[data-sortkey="' + (sortColumn + mainSort) + '-' + (rowIndex + 1) + '"]'), $table);
|
||||
return;
|
||||
}
|
||||
// Otherwise, just adjust the sortColumn
|
||||
sortColumn = sortColumn + mainSort;
|
||||
}
|
||||
|
||||
var localSignClass = $this.attr('data-defaultsign') || signClass;
|
||||
|
||||
// update arrow icon
|
||||
$table.find('th').each(function () {
|
||||
$(this).removeClass('up').removeClass('down').addClass('nosort');
|
||||
});
|
||||
|
||||
if ($.browser.mozilla) {
|
||||
var moz_arrow = $table.find('div.mozilla');
|
||||
if (moz_arrow !== undefined) {
|
||||
moz_arrow.find('.sign').remove();
|
||||
moz_arrow.parent().html(moz_arrow.html());
|
||||
}
|
||||
$this.wrapInner('<div class="mozilla"></div>');
|
||||
$this.children().eq(0).append('<span class="sign ' + localSignClass + '"></span>');
|
||||
}
|
||||
else {
|
||||
$table.find('span.sign').remove();
|
||||
$this.append('<span class="sign ' + localSignClass + '"></span>');
|
||||
}
|
||||
|
||||
// sort direction
|
||||
var sortKey = $this.attr('data-sortkey');
|
||||
var initialDirection = $this.attr('data-firstsort') !== 'desc' ? 'desc' : 'asc';
|
||||
|
||||
context.lastSort = sortKey;
|
||||
bsSort[sortKey] = (bsSort[sortKey] || initialDirection) === 'asc' ? 'desc' : 'asc';
|
||||
if (bsSort[sortKey] === 'desc') {
|
||||
$this.find('span.sign').addClass('up');
|
||||
$this.addClass('up').removeClass('down nosort');
|
||||
} else {
|
||||
$this.addClass('down').removeClass('up nosort');
|
||||
}
|
||||
|
||||
// sort rows
|
||||
var rows = $table.children('tbody').children('tr');
|
||||
sortEngine(rows, { selector: 'td:nth-child(' + (sortColumn + 1) + ')', order: bsSort[sortKey], data: 'value' });
|
||||
|
||||
// add class to sorted column cells
|
||||
$table.find('td.sorted, th.sorted').removeClass('sorted');
|
||||
rows.find('td:eq(' + sortColumn + ')').addClass('sorted');
|
||||
$this.addClass('sorted');
|
||||
}
|
||||
|
||||
// jQuery 1.9 removed this object
|
||||
if (!$.browser) {
|
||||
$.browser = { chrome: false, mozilla: false, opera: false, msie: false, safari: false };
|
||||
var ua = navigator.userAgent;
|
||||
$.each($.browser, function (c) {
|
||||
$.browser[c] = ((new RegExp(c, 'i').test(ua))) ? true : false;
|
||||
if ($.browser.mozilla && c === 'mozilla') { $.browser.mozilla = ((new RegExp('firefox', 'i').test(ua))) ? true : false; }
|
||||
if ($.browser.chrome && c === 'safari') { $.browser.safari = false; }
|
||||
});
|
||||
}
|
||||
|
||||
// Initialise on DOM ready
|
||||
$($.bootstrapSortable);
|
||||
|
||||
}(jQuery));
|
@ -10,11 +10,11 @@ function drawChart() {
|
||||
}
|
||||
|
||||
function getBoxAmounts() {
|
||||
var boxes = ['in', 'out','bills-unpaid','bills-paid'];
|
||||
var boxes = ['in', 'out', 'bills-unpaid', 'bills-paid'];
|
||||
for (x in boxes) {
|
||||
var box = boxes[x];
|
||||
$.getJSON('/json/box', {box: box}).success(function (data) {
|
||||
if(data.amount_raw != 0) {
|
||||
$.getJSON('/json/box/' + box).success(function (data) {
|
||||
if (data.amount_raw != 0) {
|
||||
$('#box-' + data.box).html(data.amount);
|
||||
}
|
||||
}).fail(function () {
|
||||
|
@ -22,13 +22,16 @@
|
||||
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.accounts')
|
||||
</div>
|
||||
@include('list.accounts')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
|
||||
@section('styles')
|
||||
<link rel="stylesheet" href="css/bootstrap-sortable.css" type="text/css" media="all" />
|
||||
@stop
|
||||
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var what = '{{{$what}}}';
|
||||
@ -39,5 +42,6 @@
|
||||
<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/accounts.js"></script>
|
||||
@stop
|
||||
|
@ -55,8 +55,6 @@
|
||||
<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/accounts.js"></script>
|
||||
|
||||
<script src="js/jquery-ui.min.js" type="text/javascript"></script>
|
||||
<script src="js/accounts.js" type="text/javascript"></script>
|
||||
@stop
|
||||
|
@ -27,6 +27,10 @@
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
@section('styles')
|
||||
<link rel="stylesheet" href="css/bootstrap-sortable.css" type="text/css" media="all" />
|
||||
@stop
|
||||
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
@ -35,5 +39,6 @@
|
||||
<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
|
||||
|
@ -1,3 +1,3 @@
|
||||
@if(isset($options['helpText']))
|
||||
<p class="help-block">{{$options['helpText']}}</p>
|
||||
@endif
|
||||
@endif
|
||||
|
@ -52,62 +52,104 @@
|
||||
<div id="categories-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-line-chart"></i> Savings
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@if(count($savings) == 0)
|
||||
<p class="small"><em>Mark your asset accounts as "Savings account" to fill this panel.</em></p>
|
||||
@else
|
||||
@foreach($savings as $account)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"><h5><a href="{{route('accounts.show')}}">{{$account->name}}</a></h5></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- start -->
|
||||
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">{!! Amount::format($account->startBalance) !!}</div>
|
||||
<!-- bar -->
|
||||
<div class="col-lg-8 col-md-8 col-sm-6 col-xs-4">
|
||||
@if($account->difference < 0)
|
||||
<!-- green (100-pct), then red (pct) -->
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success progress-bar-striped" style="width: {{100 - $account->percentage}}%">
|
||||
@if($account->percentage <= 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-danger progress-bar-striped" style="width: {{$account->percentage}}%">
|
||||
@if($account->percentage > 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<!-- green (pct), then blue (100-pct) -->
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success progress-bar-striped" style="width: {{$account->percentage}}%">
|
||||
@if($account->percentage > 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-info progress-bar-striped" style="width: {{100 - $account->percentage}}%">
|
||||
@if($account->percentage <= 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SAVINGS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-line-chart"></i> Savings
|
||||
<span class="pull-right">{!! Amount::format($savingsTotal) !!}</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@if(count($savings) == 0)
|
||||
<p class="small"><em>Mark your asset accounts as "Savings account" to fill this panel.</em></p>
|
||||
@else
|
||||
@foreach($savings as $account)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"><h5><a href="{{route('accounts.show')}}">{{$account->name}}</a></h5></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- start -->
|
||||
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">{!! Amount::format($account->startBalance) !!}</div>
|
||||
<!-- bar -->
|
||||
<div class="col-lg-8 col-md-8 col-sm-6 col-xs-4">
|
||||
@if($account->difference < 0)
|
||||
<!-- green (100-pct), then red (pct) -->
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success progress-bar-striped" style="width: {{100 - $account->percentage}}%">
|
||||
@if($account->percentage <= 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-danger progress-bar-striped" style="width: {{$account->percentage}}%">
|
||||
@if($account->percentage > 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<!-- green (pct), then blue (100-pct) -->
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success progress-bar-striped" style="width: {{$account->percentage}}%">
|
||||
@if($account->percentage > 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-info progress-bar-striped" style="width: {{100 - $account->percentage}}%">
|
||||
@if($account->percentage <= 50)
|
||||
{{Amount::format($account->difference,false)}}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<!-- end -->
|
||||
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">{!! Amount::format($account->endBalance) !!}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PIGGY BANKS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-sort-amount-asc fa-fw"></i> Piggy banks
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@if($piggyBankAccounts->count() == 0)
|
||||
<p class="small"><em>Create piggy banks to fill this panel.</em></p>
|
||||
@else
|
||||
@foreach($piggyBankAccounts as $account)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"><h5><a href="{{route('accounts.show')}}">{{$account->name}}</a></h5></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- start -->
|
||||
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">{!! Amount::format($account->startBalance) !!}</div>
|
||||
<!-- bar -->
|
||||
<div class="col-lg-8 col-md-8 col-sm-6 col-xs-4">
|
||||
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-info progress-bar-striped" style="width: {{100 - $account->percentage}}%">
|
||||
@if($account->percentage <= 50)
|
||||
{{Amount::format($account->piggyBalance,false)}} divided
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<!-- end -->
|
||||
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">{!! Amount::format($account->endBalance) !!}</div>
|
||||
<div class="progress-bar progress-bar-success progress-bar-striped" style="width: {{$account->percentage}}%">
|
||||
@if($account->percentage > 50)
|
||||
{{Amount::format($account->difference,false)}} left to divide
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end -->
|
||||
<div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">{!! Amount::format($account->piggyBalance) !!}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,9 +1,7 @@
|
||||
@if(is_object($accounts) && method_exists($accounts, 'render'))
|
||||
{!! $accounts->render() !!}
|
||||
@endif
|
||||
<table class="table table-striped table-bordered">
|
||||
<table class="table table-striped table-bordered sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th data-defaultsort="disabled"> </th>
|
||||
<th>Name</th>
|
||||
@if(isset($what) && $what == 'asset')
|
||||
<th>Role</th>
|
||||
@ -13,6 +11,8 @@
|
||||
<th>Last activity</th>
|
||||
<th>Balance difference between {{Session::get('start')->format('jS F Y')}} and {{Session::get('end')->format('jS F Y')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($accounts as $account)
|
||||
<tr>
|
||||
<td>
|
||||
@ -31,29 +31,30 @@
|
||||
@endforeach
|
||||
</td>
|
||||
@endif
|
||||
<td>{!! Amount::format(Steam::balance($account)) !!}</td>
|
||||
<td>
|
||||
<?php $balance = Steam::balance($account);?>
|
||||
<td data-value="{{$balance}}">{!! Amount::format($balance) !!}</td>
|
||||
<td data-value="{{intval($account->active)}}">
|
||||
@if($account->active)
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
@else
|
||||
<i class="fa fa-fw fa-ban"></i>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if($account->lastActivityDate)
|
||||
{{{$account->lastActivityDate->format('j F Y')}}}
|
||||
<td data-value="{{$account->lastActivityDate->format('U')}}">
|
||||
{{{$account->lastActivityDate->format('j F Y')}}}
|
||||
</td>
|
||||
@else
|
||||
<em>Never</em>
|
||||
<td data-value="0">
|
||||
<em>Never</em>
|
||||
</td>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<td data-value="{{$account->endBalance - $account->startBalance}}">
|
||||
{!! Amount::format($account->endBalance - $account->startBalance) !!}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
@endforeach
|
||||
</table>
|
||||
@if(is_object($accounts) && method_exists($accounts, 'render'))
|
||||
{!! $accounts->render() !!}
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
@ -1,9 +1,12 @@
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>Name</th>
|
||||
<th>Last activity</th>
|
||||
</tr>
|
||||
<table class="table table-striped table-bordered sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-defaultsort="disabled"> </th>
|
||||
<th>Name</th>
|
||||
<th>Last activity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><a href="{{route('categories.noCategory')}}"><em>Without a category</em></a></td>
|
||||
@ -20,13 +23,16 @@
|
||||
<td>
|
||||
<a href="{{route('categories.show',$category->id)}}" title="{{{$category->name}}}">{{{$category->name}}}</a>
|
||||
</td>
|
||||
<td>
|
||||
@if($category->lastActivity)
|
||||
@if($category->lastActivity)
|
||||
<td data-value="{{$category->lastActivity->format('U')}}">
|
||||
{{$category->lastActivity->format('jS F Y')}}
|
||||
@else
|
||||
</td>
|
||||
@else
|
||||
<td data-value="0">
|
||||
<em>Never</em>
|
||||
@endif
|
||||
</td>
|
||||
</td>
|
||||
@endif
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -75,7 +75,7 @@
|
||||
@foreach($budgets as $id => $budget)
|
||||
<tr>
|
||||
<td>{{{$budget['name']}}}</td>
|
||||
<td>{!! Amount::format($budget['amount']) !!}</td>
|
||||
<td>{!! Amount::format($budget['queryAmount']) !!}</td>
|
||||
<?php $spent = 0;?>
|
||||
@foreach($accounts as $account)
|
||||
@if($account->hide === false)
|
||||
@ -83,23 +83,23 @@
|
||||
<td>
|
||||
@if($id == 0)
|
||||
<a href="{{route('reports.no-budget',[$account, $year, $month])}}" class="openModal">
|
||||
{!! Amount::format($account->budgetInformation[$id]['amount']) !!}
|
||||
{!! Amount::format($account->budgetInformation[$id]['queryAmount']) !!}
|
||||
</a>
|
||||
@else
|
||||
{!! Amount::format($account->budgetInformation[$id]['amount']) !!}
|
||||
{!! Amount::format($account->budgetInformation[$id]['queryAmount']) !!}
|
||||
@endif
|
||||
</td>
|
||||
<?php
|
||||
$spent += floatval($account->budgetInformation[$id]['amount']);
|
||||
$accountSums[$account->id] += floatval($account->budgetInformation[$id]['amount']);
|
||||
$spent += floatval($account->budgetInformation[$id]['queryAmount']);
|
||||
$accountSums[$account->id] += floatval($account->budgetInformation[$id]['queryAmount']);
|
||||
?>
|
||||
@else
|
||||
<td>{!! Amount::format(0) !!}</td>
|
||||
@endif
|
||||
@endif
|
||||
@endforeach
|
||||
<td>{!! Amount::format($budget['amount'] + $budget['spent']) !!}</td>
|
||||
<td>{!! Amount::format($budget['amount'] + $spent) !!}</td>
|
||||
<td>{!! Amount::format($budget['queryAmount'] + $budget['spent']) !!}</td>
|
||||
<td>{!! Amount::format($budget['queryAmount'] + $spent) !!}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
<tr>
|
||||
@ -122,10 +122,10 @@
|
||||
@if($account->hide === false)
|
||||
@if(isset($account->budgetInformation[0]))
|
||||
<td>
|
||||
@if($account->budgetInformation[0]['amount'] + $account->balancedAmount != 0.0)
|
||||
<a href="{{route('reports.left-unbalanced',[$account, $year, $month])}}" class="openModal">{!! Amount::format($account->budgetInformation[0]['amount'] + $account->balancedAmount) !!}</a>
|
||||
@if($account->budgetInformation[0]['queryAmount'] + $account->balancedAmount != 0.0)
|
||||
<a href="{{route('reports.left-unbalanced',[$account, $year, $month])}}" class="openModal">{!! Amount::format($account->budgetInformation[0]['queryAmount'] + $account->balancedAmount) !!}</a>
|
||||
@else
|
||||
{!! Amount::format($account->budgetInformation[0]['amount'] + $account->balancedAmount) !!}
|
||||
{!! Amount::format($account->budgetInformation[0]['queryAmount'] + $account->balancedAmount) !!}
|
||||
@endif
|
||||
</td>
|
||||
@else
|
||||
|
@ -64,7 +64,7 @@
|
||||
<?php $sum = 0;?>
|
||||
@foreach($expenses as $id => $expense)
|
||||
<?php
|
||||
$sum += floatval($expense['amount']);
|
||||
$sum += floatval($expense['queryAmount']);
|
||||
?>
|
||||
<tr>
|
||||
@if($id > 0)
|
||||
@ -72,7 +72,7 @@
|
||||
@else
|
||||
<td><em>{{{$expense['name']}}}</em></td>
|
||||
@endif
|
||||
<td>{!! Amount::format($expense['amount']) !!}</td>
|
||||
<td>{!! Amount::format($expense['queryAmount']) !!}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
<tr>
|
||||
@ -133,11 +133,11 @@
|
||||
@foreach($budgets as $id => $budget)
|
||||
<?php
|
||||
$sumSpent += $budget['spent'];
|
||||
$sumEnvelope += $budget['amount'];
|
||||
$sumLeft += $budget['amount'] + $budget['spent'];
|
||||
$sumEnvelope += $budget['queryAmount'];
|
||||
$sumLeft += $budget['queryAmount'] + $budget['spent'];
|
||||
?>
|
||||
<!-- only display when relevant: -->
|
||||
@if($budget['amount'] != 0 || $budget['spent'] != 0)
|
||||
@if($budget['queryAmount'] != 0 || $budget['spent'] != 0)
|
||||
<tr>
|
||||
<td>
|
||||
@if($id > 0)
|
||||
@ -146,9 +146,9 @@
|
||||
<em>{{{$budget['name']}}}</em>
|
||||
@endif
|
||||
</td>
|
||||
<td>{!! Amount::format($budget['amount']) !!}</td>
|
||||
<td>{!! Amount::format($budget['queryAmount']) !!}</td>
|
||||
<td>{!! Amount::format($budget['spent'],false) !!}</td>
|
||||
<td>{!! Amount::format($budget['amount'] + $budget['spent']) !!}</td>
|
||||
<td>{!! Amount::format($budget['queryAmount'] + $budget['spent']) !!}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@endforeach
|
||||
@ -174,7 +174,7 @@
|
||||
</tr>
|
||||
<?php $sum = 0;?>
|
||||
@foreach($categories as $id => $category)
|
||||
<?php $sum += floatval($category['amount']);?>
|
||||
<?php $sum += floatval($category['queryAmount']);?>
|
||||
<tr>
|
||||
<td>
|
||||
@if($id > 0)
|
||||
@ -183,7 +183,7 @@
|
||||
<em>{{{$category['name']}}}</em>
|
||||
@endif
|
||||
</td>
|
||||
<td>{!! Amount::format($category['amount'],false) !!}</td>
|
||||
<td>{!! Amount::format($category['queryAmount'],false) !!}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
<tr>
|
||||
|
@ -92,10 +92,10 @@
|
||||
$incomeSum = 0;
|
||||
$expenseSum = 0;
|
||||
foreach($groupedIncomes as $income) {
|
||||
$incomeSum += floatval($income->amount);
|
||||
$incomeSum += floatval($income->queryAmount);
|
||||
}
|
||||
foreach($groupedExpenses as $exp) {
|
||||
$expenseSum += floatval($exp['amount']);
|
||||
$expenseSum += floatval($exp['queryAmount']);
|
||||
}
|
||||
$incomeSum = floatval($incomeSum*-1);
|
||||
|
||||
@ -127,11 +127,11 @@
|
||||
<?php $sum = 0;?>
|
||||
@foreach($groupedIncomes as $income)
|
||||
<?php
|
||||
$sum += floatval($income->amount)*-1;
|
||||
$sum += floatval($income->queryAmount)*-1;
|
||||
?>
|
||||
<tr>
|
||||
<td><a href="{{route('accounts.show',$income->account_id)}}">{{{$income->name}}}</a></td>
|
||||
<td>{!! Amount::format(floatval($income->amount)*-1) !!}</td>
|
||||
<td>{!! Amount::format(floatval($income->queryAmount)*-1) !!}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
<tr>
|
||||
@ -149,12 +149,12 @@
|
||||
</div>
|
||||
<table class="table">
|
||||
<?php $sum = 0;?>
|
||||
@foreach($groupedExpenses as $id => $expense)
|
||||
@foreach($groupedExpenses as $expense)
|
||||
<tr>
|
||||
<td><a href="{{route('accounts.show',$id)}}">{{{$expense['name']}}}</a></td>
|
||||
<td>{!! Amount::format(floatval($expense['amount'])*-1) !!}</td>
|
||||
<td><a href="{{route('accounts.show',$expense['id'])}}">{{{$expense['name']}}}</a></td>
|
||||
<td>{!! Amount::format(floatval($expense['queryAmount'])*-1) !!}</td>
|
||||
</tr>
|
||||
<?php $sum += floatval($expense['amount'])*-1;?>
|
||||
<?php $sum += floatval($expense['queryAmount'])*-1;?>
|
||||
@endforeach
|
||||
<tr>
|
||||
<td><em>Sum</em></td>
|
||||
|
@ -91,6 +91,9 @@
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var what = "{{$what}}";
|
||||
</script>
|
||||
<script type="text/javascript" src="js/bootstrap3-typeahead.min.js"></script>
|
||||
<script type="text/javascript" src="js/transactions.js"></script>
|
||||
@stop
|
||||
|
@ -22,16 +22,6 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
||||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run.
|
||||
*
|
||||
* @since Method available since Release 3.4.0
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the fixture, for example, opens a network connection.
|
||||
* This method is called before a test is executed.
|
||||
@ -44,7 +34,15 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run.
|
||||
*
|
||||
* @since Method available since Release 3.4.0
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
@ -61,5 +59,4 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\FactoryMuffin\Facade as FactoryMuffin;
|
||||
|
||||
@ -95,12 +96,15 @@ class AccountControllerTest extends TestCase
|
||||
$account = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
|
||||
$this->be($account->user);
|
||||
$this->assertCount(1, DB::table('accounts')->where('id', $account->id)->whereNull('deleted_at')->get());
|
||||
|
||||
// mock:
|
||||
$repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$repository->shouldReceive('destroy')->andReturn(true);
|
||||
|
||||
// post it!
|
||||
$this->call('POST', '/accounts/destroy/' . $account->id, ['_token' => 'replaceme']);
|
||||
$this->assertSessionHas('success');
|
||||
$this->assertCount(0, DB::table('accounts')->where('id', $account->id)->whereNull('deleted_at')->get());
|
||||
$this->assertResponseStatus(302);
|
||||
}
|
||||
|
||||
public function testEdit()
|
||||
@ -167,7 +171,10 @@ class AccountControllerTest extends TestCase
|
||||
// an account:
|
||||
$this->be($this->account->user);
|
||||
|
||||
// mock!
|
||||
Amount::shouldReceive('getCurrencyCode')->once()->andReturn('A');
|
||||
$repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$repository->shouldReceive('getJournals')->andReturn(new LengthAwarePaginator([], 0, 10));
|
||||
|
||||
// get edit page:
|
||||
$this->call('GET', '/accounts/show/' . $this->account->id);
|
||||
|
@ -93,6 +93,9 @@ class BillControllerTest extends TestCase
|
||||
$bill = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
$this->be($bill->user);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$repository->shouldReceive('destroy')->andReturn(true);
|
||||
|
||||
|
||||
$this->call('POST', '/bills/destroy/' . $bill->id, ['_token' => 'replaceMe']);
|
||||
$this->assertSessionHas('success', 'The bill was deleted.');
|
||||
|
@ -78,12 +78,13 @@ class BudgetControllerTest extends TestCase
|
||||
$budget = FactoryMuffin::create('FireflyIII\Models\Budget');
|
||||
$this->be($budget->user);
|
||||
|
||||
$this->assertCount(1, DB::table('budgets')->where('id', $budget->id)->get());
|
||||
$repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$repository->shouldReceive('destroy')->andReturn(true);
|
||||
|
||||
$this->call('POST', '/budgets/destroy/' . $budget->id, ['_token' => 'replaceme']);
|
||||
|
||||
$this->assertSessionHas('success', 'The budget "' . e($budget->name) . '" was deleted.');
|
||||
$this->assertCount(0, DB::table('budgets')->wherenull('deleted_at')->where('id', $budget->id)->get());
|
||||
|
||||
}
|
||||
|
||||
public function testEdit()
|
||||
|
@ -146,12 +146,18 @@ class CategoryControllerTest extends TestCase
|
||||
|
||||
public function testStore()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
|
||||
$repository->shouldReceive('store')->andReturn($category);
|
||||
// create
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$this->be($category->user);
|
||||
|
||||
// mock
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$request = $this->mock('FireflyIII\Http\Requests\CategoryFormRequest');
|
||||
|
||||
// expect
|
||||
$repository->shouldReceive('store')->andReturn($category);
|
||||
$request->shouldReceive('input')->andReturn('');
|
||||
|
||||
$this->call('POST', '/categories/store', ['_token' => 'replaceMe', 'name' => 'Bla bla #' . rand(1, 1000)]);
|
||||
$this->assertResponseStatus(302);
|
||||
$this->assertSessionHas('success', 'New category "' . $category->name . '" stored!');
|
||||
@ -160,12 +166,19 @@ class CategoryControllerTest extends TestCase
|
||||
//
|
||||
public function testStoreAndRedirect()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
|
||||
$repository->shouldReceive('store')->andReturn($category);
|
||||
// create
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$this->be($category->user);
|
||||
|
||||
// mock:
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$request = $this->mock('FireflyIII\Http\Requests\CategoryFormRequest');
|
||||
|
||||
// fake:
|
||||
$repository->shouldReceive('store')->andReturn($category);
|
||||
$request->shouldReceive('input')->andReturn('');
|
||||
|
||||
|
||||
$this->call('POST', '/categories/store', ['_token' => 'replaceMe', 'create_another' => 1, 'name' => 'Bla bla #' . rand(1, 1000)]);
|
||||
$this->assertResponseStatus(302);
|
||||
$this->assertSessionHas('success', 'New category "' . $category->name . '" stored!');
|
||||
@ -173,12 +186,18 @@ class CategoryControllerTest extends TestCase
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
|
||||
$repository->shouldReceive('update')->andReturn($category);
|
||||
// create
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$this->be($category->user);
|
||||
|
||||
// mock
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$request = $this->mock('FireflyIII\Http\Requests\CategoryFormRequest');
|
||||
|
||||
// expect
|
||||
$repository->shouldReceive('update')->andReturn($category);
|
||||
$request->shouldReceive('input')->andReturn('');
|
||||
|
||||
$this->call('POST', '/categories/update/' . $category->id, ['_token' => 'replaceMe', 'name' => 'Bla bla #' . rand(1, 1000)]);
|
||||
$this->assertResponseStatus(302);
|
||||
$this->assertSessionHas('success', 'Category "' . $category->name . '" updated.');
|
||||
@ -186,12 +205,19 @@ class CategoryControllerTest extends TestCase
|
||||
|
||||
public function testUpdateAndRedirect()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
|
||||
$repository->shouldReceive('update')->andReturn($category);
|
||||
// create
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$this->be($category->user);
|
||||
|
||||
// mock
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$request = $this->mock('FireflyIII\Http\Requests\CategoryFormRequest');
|
||||
|
||||
// expect
|
||||
$request->shouldReceive('input')->andReturn('');
|
||||
$repository->shouldReceive('update')->andReturn($category);
|
||||
|
||||
|
||||
$this->call('POST', '/categories/update/' . $category->id, ['_token' => 'replaceMe', 'return_to_edit' => 1, 'name' => 'Bla bla #' . rand(1, 1000)]);
|
||||
$this->assertResponseStatus(302);
|
||||
$this->assertSessionHas('success', 'Category "' . $category->name . '" updated.');
|
||||
|
339
tests/controllers/GoogleChartControllerTest.php
Normal file
339
tests/controllers/GoogleChartControllerTest.php
Normal file
@ -0,0 +1,339 @@
|
||||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Preference;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\FactoryMuffin\Facade as FactoryMuffin;
|
||||
|
||||
/**
|
||||
* Class GoogleChartControllerTest
|
||||
*/
|
||||
class GoogleChartControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Sets up the fixture, for example, opens a network connection.
|
||||
* This method is called before a test is executed.
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run.
|
||||
*
|
||||
* @since Method available since Release 3.4.0
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down the fixture, for example, closes a network connection.
|
||||
* This method is called after a test is executed.
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
}
|
||||
|
||||
public function testAccountBalanceChart()
|
||||
{
|
||||
$account = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$this->be($account->user);
|
||||
|
||||
// mock stuff:
|
||||
Steam::shouldReceive('balance')->andReturn(0);
|
||||
|
||||
$this->call('GET', '/chart/account/' . $account->id);
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testAllAccountsBalanceChart()
|
||||
{
|
||||
$account = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$this->be($account->user);
|
||||
$collection = new Collection;
|
||||
$collection->push($account);
|
||||
|
||||
//mock stuff:
|
||||
Preferences::shouldReceive('get')->andReturn(new Preference);
|
||||
$repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$repository->shouldReceive('getFrontpageAccounts')->andReturn($collection);
|
||||
|
||||
$this->call('GET', '/chart/home/account');
|
||||
$this->assertResponseOk();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testAllBudgetsAndSpending()
|
||||
{
|
||||
$budget = FactoryMuffin::create('FireflyIII\Models\Budget');
|
||||
$this->be($budget->user);
|
||||
$collection = new Collection;
|
||||
$collection->push($budget);
|
||||
|
||||
// mock stuff:
|
||||
$repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$repository->shouldReceive('getBudgets')->andReturn($collection);
|
||||
$repository->shouldReceive('spentInMonth')->andReturn(rand(1, 100));
|
||||
|
||||
$this->call('GET', '/chart/budgets/spending/2015');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testAllBudgetsHomeChart()
|
||||
{
|
||||
$budget = FactoryMuffin::create('FireflyIII\Models\Budget');
|
||||
$budget1 = FactoryMuffin::create('FireflyIII\Models\Budget');
|
||||
$this->be($budget->user);
|
||||
|
||||
$start = Carbon::now()->startOfMonth();
|
||||
$end = Carbon::now()->endOfMonth();
|
||||
|
||||
$repetition = FactoryMuffin::create('FireflyIII\Models\LimitRepetition');
|
||||
$repetitions = new Collection;
|
||||
$repetitions->push($repetition);
|
||||
$emptyRepetitions = new Collection;
|
||||
|
||||
$collection = new Collection;
|
||||
$collection->push($budget);
|
||||
$collection->push($budget1);
|
||||
|
||||
// mock stuff:
|
||||
$repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$repository->shouldReceive('getBudgets')->andReturn($collection);
|
||||
$repository->shouldReceive('getBudgetLimitRepetitions')->once()->andReturn($repetitions, $emptyRepetitions);
|
||||
$repository->shouldReceive('sumBudgetExpensesInPeriod')->andReturn(12);
|
||||
$repository->shouldReceive('getWithoutBudgetSum')->andReturn(0);
|
||||
|
||||
$this->call('GET', '/chart/home/budgets');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testAllCategoriesHomeChart()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
|
||||
$this->be($category->user);
|
||||
$category->save();
|
||||
$category->sum = 100;
|
||||
$collection = new Collection;
|
||||
$collection->push($category);
|
||||
|
||||
// mock stuff:
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$repository->shouldReceive('getCategoriesAndExpenses')->andReturn($collection);
|
||||
Crypt::shouldReceive('decrypt')->andReturn('Hello!');
|
||||
Crypt::shouldReceive('encrypt')->andReturn('Hello!');
|
||||
|
||||
|
||||
$this->call('GET', '/chart/home/categories');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testBillOverview()
|
||||
{
|
||||
$bill = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
$journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$collection = new Collection;
|
||||
$collection->push($journal);
|
||||
$this->be($bill->user);
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$repository->shouldReceive('getJournals')->andReturn($collection);
|
||||
|
||||
|
||||
// call!
|
||||
$this->call('GET', '/chart/bills/' . $bill->id);
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testBillsOverview()
|
||||
{
|
||||
$bill1 = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
$bill2 = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
$journal1 = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$journal2 = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$card1 = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$card2 = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$fake = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
|
||||
|
||||
$bills = new Collection([$bill1, $bill2]);
|
||||
$journals = new Collection([$journal1, $journal2]);
|
||||
$cards = new Collection([$card1, $card2]);
|
||||
$emptyCollection = new Collection;
|
||||
$ranges = [['start' => new Carbon, 'end' => new Carbon]];
|
||||
$this->be($bill1->user);
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
|
||||
// calls:
|
||||
$repository->shouldReceive('getActiveBills')->andReturn($bills);
|
||||
$repository->shouldReceive('getRanges')->andReturn($ranges);
|
||||
$repository->shouldReceive('getJournalsInRange')->andReturn($journals, $emptyCollection);
|
||||
$accounts->shouldReceive('getCreditCards')->andReturn($cards);
|
||||
$accounts->shouldReceive('getTransfersInRange')->andReturn($journals, $emptyCollection);
|
||||
$repository->shouldReceive('createFakeBill')->andReturn($fake);
|
||||
Steam::shouldReceive('balance')->andReturn(-1, 0);
|
||||
|
||||
$this->call('GET', '/chart/home/bills');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testBudgetLimitSpending()
|
||||
{
|
||||
$repetition = FactoryMuffin::create('FireflyIII\Models\LimitRepetition');
|
||||
$repetition->startdate = Carbon::now()->startOfMonth();
|
||||
$repetition->enddate = Carbon::now()->endOfMonth();
|
||||
$repetition->save();
|
||||
$budget = $repetition->budgetlimit->budget;
|
||||
$this->be($budget->user);
|
||||
///chart/budget/{budget}/{limitrepetition}
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$repository->shouldReceive('expensesOnDay')->andReturn(rand(1, 1000));
|
||||
|
||||
$this->call('GET', '/chart/budget/' . $budget->id . '/' . $repetition->id);
|
||||
$this->assertResponseOk();
|
||||
|
||||
}
|
||||
|
||||
public function testBudgetsAndSpending()
|
||||
{
|
||||
$budget = FactoryMuffin::create('FireflyIII\Models\Budget');
|
||||
$this->be($budget->user);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$repository->shouldReceive('spentInMonth')->andReturn(100);
|
||||
$repository->shouldReceive('getLimitAmountOnDate')->andReturn(100);
|
||||
$repository->shouldReceive('getFirstBudgetLimitDate')->andReturn(Carbon::now()->startOfMonth());
|
||||
$repository->shouldReceive('getLastBudgetLimitDate')->andReturn(Carbon::now()->endOfYear());
|
||||
|
||||
// /chart/budget/{budget}/spending/{year?}
|
||||
$this->call('GET', '/chart/budget/' . $budget->id . '/spending/0');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testBudgetsAndSpendingWithYear()
|
||||
{
|
||||
$budget = FactoryMuffin::create('FireflyIII\Models\Budget');
|
||||
$this->be($budget->user);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$repository->shouldReceive('spentInMonth')->andReturn(100);
|
||||
$repository->shouldReceive('getLimitAmountOnDate')->andReturn(100);
|
||||
|
||||
// /chart/budget/{budget}/spending/{year?}
|
||||
$this->call('GET', '/chart/budget/' . $budget->id . '/spending/2015');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testCategoryOverviewChart()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$pref = FactoryMuffin::create('FireflyIII\Models\Preference');
|
||||
$this->be($category->user);
|
||||
$start = new Carbon();
|
||||
$start->subDay();
|
||||
$end = new Carbon;
|
||||
$end->addWeek();
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$repository->shouldReceive('getFirstActivityDate')->andReturn($start);
|
||||
$repository->shouldReceive('spentInPeriodSum')->andReturn(rand(1, 100));
|
||||
Preferences::shouldReceive('get')->andReturn($pref);
|
||||
|
||||
Navigation::shouldReceive('startOfPeriod')->andReturn($start);
|
||||
Navigation::shouldReceive('endOfPeriod')->andReturn($start);
|
||||
Navigation::shouldReceive('addPeriod')->andReturn($end);
|
||||
|
||||
$this->call('GET', '/chart/category/' . $category->id . '/overview');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testCategoryPeriodChart()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$this->be($category->user);
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$repository->shouldReceive('spentOnDaySum')->andReturn(rand(1, 100));
|
||||
|
||||
$this->call('GET', '/chart/category/' . $category->id . '/period');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testPiggyBankHistory()
|
||||
{
|
||||
$piggyBank = FactoryMuffin::create('FireflyIII\Models\PiggyBank');
|
||||
$this->be($piggyBank->account->user);
|
||||
|
||||
$obj = new stdClass;
|
||||
$obj->sum = 12;
|
||||
$obj->date = new Carbon;
|
||||
$collection = new Collection([$obj]);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface');
|
||||
$repository->shouldReceive('getEventSummarySet')->andReturn($collection);
|
||||
|
||||
$this->call('GET', '/chart/piggy-history/' . $piggyBank->id);
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testYearInExp()
|
||||
{
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$preference = FactoryMuffin::create('FireflyIII\Models\Preference');
|
||||
$journal1 = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$journal2 = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$journals = new Collection([$journal1, $journal2]);
|
||||
$this->be($user);
|
||||
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Helpers\Report\ReportQueryInterface');
|
||||
|
||||
// expect!
|
||||
$repository->shouldReceive('incomeByPeriod')->andReturn($journals);
|
||||
$repository->shouldReceive('journalsByExpenseAccount')->andReturn($journals);
|
||||
Preferences::shouldReceive('get')->withArgs(['showSharedReports', false])->once()->andReturn($preference);
|
||||
|
||||
|
||||
$this->call('GET', '/chart/reports/income-expenses/2015');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testYearInExpSum()
|
||||
{
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$preference = FactoryMuffin::create('FireflyIII\Models\Preference');
|
||||
$journal1 = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$journal2 = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$journals = new Collection([$journal1, $journal2]);
|
||||
$this->be($user);
|
||||
|
||||
|
||||
// mock!
|
||||
$repository = $this->mock('FireflyIII\Helpers\Report\ReportQueryInterface');
|
||||
|
||||
// expect!
|
||||
$repository->shouldReceive('incomeByPeriod')->andReturn($journals);
|
||||
$repository->shouldReceive('journalsByExpenseAccount')->andReturn($journals);
|
||||
Preferences::shouldReceive('get')->withArgs(['showSharedReports', false])->once()->andReturn($preference);
|
||||
|
||||
|
||||
$this->call('GET', '/chart/reports/income-expenses-sum/2015');
|
||||
}
|
||||
|
||||
}
|
98
tests/controllers/HelpControllerTest.php
Normal file
98
tests/controllers/HelpControllerTest.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
use League\FactoryMuffin\Facade as FactoryMuffin;
|
||||
|
||||
/**
|
||||
* Class HelpControllerTest
|
||||
*/
|
||||
class HelpControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Sets up the fixture, for example, opens a network connection.
|
||||
* This method is called before a test is executed.
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run.
|
||||
*
|
||||
* @since Method available since Release 3.4.0
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down the fixture, for example, closes a network connection.
|
||||
* This method is called after a test is executed.
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything present and accounted for, and in cache:
|
||||
*/
|
||||
public function testGetHelpText()
|
||||
{
|
||||
// login
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
// mock some stuff.
|
||||
$interface = $this->mock('FireflyIII\Helpers\Help\HelpInterface');
|
||||
$interface->shouldReceive('hasRoute')->once()->with('accounts.index')->andReturn(true);
|
||||
$interface->shouldReceive('getFromCache')->once()->with('help.accounts.index.title')->andReturn('Title.');
|
||||
$interface->shouldReceive('getFromCache')->once()->with('help.accounts.index.text')->andReturn('Text');
|
||||
$interface->shouldReceive('inCache')->andReturn(true);
|
||||
|
||||
|
||||
$this->call('GET', '/help/accounts.index');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything present and accounted for, but not cached
|
||||
*/
|
||||
public function testGetHelpTextNoCache()
|
||||
{
|
||||
// login
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$content = ['title' => 'Bla', 'text' => 'Bla'];
|
||||
|
||||
$this->be($user);
|
||||
// mock some stuff.
|
||||
$interface = $this->mock('FireflyIII\Helpers\Help\HelpInterface');
|
||||
$interface->shouldReceive('hasRoute')->once()->with('accounts.index')->andReturn(true);
|
||||
$interface->shouldReceive('getFromGithub')->once()->with('accounts.index')->andReturn($content);
|
||||
$interface->shouldReceive('putInCache')->once()->withArgs(['accounts.index', $content]);
|
||||
$interface->shouldReceive('inCache')->once()->andReturn(false);
|
||||
|
||||
|
||||
$this->call('GET', '/help/accounts.index');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
/**
|
||||
* No such route.
|
||||
*/
|
||||
public function testGetHelpTextNoRoute()
|
||||
{
|
||||
// login
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
|
||||
$this->be($user);
|
||||
// mock some stuff.
|
||||
$interface = $this->mock('FireflyIII\Helpers\Help\HelpInterface');
|
||||
$interface->shouldReceive('hasRoute')->once()->with('accounts.index')->andReturn(false);
|
||||
|
||||
|
||||
$this->call('GET', '/help/accounts.index');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use League\FactoryMuffin\Facade as FactoryMuffin;
|
||||
|
||||
/**
|
||||
* Generated by PHPUnit_SkeletonGenerator on 2015-03-08 at 20:05:14.
|
||||
* Class HomeControllerTest
|
||||
*/
|
||||
class HomeControllerTest extends TestCase
|
||||
{
|
||||
@ -13,7 +16,6 @@ class HomeControllerTest extends TestCase
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
Artisan::call('migrate');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -25,6 +27,26 @@ class HomeControllerTest extends TestCase
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers FireflyIII\Http\Controllers\HomeController::dateRange
|
||||
*/
|
||||
public function testDateRange()
|
||||
{
|
||||
$start = '2015-03-01';
|
||||
$end = '2015-03-31';
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
|
||||
$this->call('POST', '/daterange', ['end' => $end, 'start' => $start, '_token' => 'replaceme']);
|
||||
$this->assertResponseOk();
|
||||
|
||||
$this->assertSessionHas('start');
|
||||
$this->assertSessionHas('end');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers FireflyIII\Http\Controllers\HomeController::dateRange
|
||||
*/
|
||||
@ -32,55 +54,62 @@ class HomeControllerTest extends TestCase
|
||||
{
|
||||
$start = '2014-03-01';
|
||||
$end = '2015-03-31';
|
||||
$this->be(new FireflyIII\User);
|
||||
$this->call('POST', '/daterange', ['end' => $end, 'start' => $start,'_token' => 'replaceme']);
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
$this->call('POST', '/daterange', ['end' => $end, 'start' => $start, '_token' => 'replaceme']);
|
||||
$this->assertResponseOk();
|
||||
|
||||
$this->assertSessionHas('start');
|
||||
$this->assertSessionHas('end');
|
||||
$this->assertSessionHas('warning');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers FireflyIII\Http\Controllers\HomeController::dateRange
|
||||
*
|
||||
*/
|
||||
public function testDateRange()
|
||||
public function testFlush()
|
||||
{
|
||||
$start = '2015-03-01';
|
||||
$end = '2015-03-31';
|
||||
$this->be(new FireflyIII\User);
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
|
||||
$this->call('POST', '/daterange', ['end' => $end, 'start' => $start,'_token' => 'replaceme']);
|
||||
$this->assertResponseOk();
|
||||
|
||||
$this->assertSessionHas('start');
|
||||
$this->assertSessionHas('end');
|
||||
$this->call('GET', '/flush');
|
||||
$this->assertResponseStatus(302);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers FireflyIII\Http\Controllers\HomeController::index
|
||||
*/
|
||||
public function testIndexLoggedIn()
|
||||
public function testIndex()
|
||||
{
|
||||
$this->be(new FireflyIII\User);
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$preference = FactoryMuffin::create('FireflyIII\Models\Preference');
|
||||
$journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$journals = new Collection([$journal]);
|
||||
$account = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$accounts = new Collection([$account]);
|
||||
$repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
|
||||
$this->be($user);
|
||||
|
||||
// mock ALL THE THINGS!
|
||||
$repository->shouldReceive('countAccounts')->once()->andReturn(3);
|
||||
Preferences::shouldReceive('get')->once()->withArgs(['frontPageAccounts', []])->andReturn($preference);
|
||||
$repository->shouldReceive('getFrontpageAccounts')->once()->with($preference)->andReturn($accounts);
|
||||
$repository->shouldReceive('getSavingsAccounts')->once()->andReturn($accounts);
|
||||
$repository->shouldReceive('getPiggyBankAccounts')->once()->andReturn($accounts);
|
||||
$repository->shouldReceive('sumOfEverything')->once()->andReturn(1);
|
||||
$repository->shouldReceive('getFrontpageTransactions')->once()->andReturn($journals);
|
||||
|
||||
|
||||
Amount::shouldReceive('getCurrencyCode')->andReturn('EUR');
|
||||
Amount::shouldReceive('format')->andReturn('xxx');
|
||||
Amount::shouldReceive('formatJournal')->with($journal)->andReturn('xxx');
|
||||
|
||||
$response = $this->call('GET', '/');
|
||||
$this->call('GET', '/');
|
||||
$this->assertResponseOk();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers FireflyIII\Http\Controllers\HomeController::index
|
||||
*/
|
||||
public function testIndexNoLogin()
|
||||
{
|
||||
$response = $this->call('GET', '/');
|
||||
$this->assertRedirectedTo('auth/login');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
206
tests/controllers/JsonControllerTest.php
Normal file
206
tests/controllers/JsonControllerTest.php
Normal file
@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use League\FactoryMuffin\Facade as FactoryMuffin;
|
||||
|
||||
/**
|
||||
* Class JsonControllerTest
|
||||
*/
|
||||
class JsonControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Sets up the fixture, for example, opens a network connection.
|
||||
* This method is called before a test is executed.
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before the first test of this test class is run.
|
||||
*
|
||||
* @since Method available since Release 3.4.0
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down the fixture, for example, closes a network connection.
|
||||
* This method is called after a test is executed.
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
}
|
||||
|
||||
public function testBoxBillsPaid()
|
||||
{
|
||||
$bill = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
$cc = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$ccs = new Collection([$cc]);
|
||||
$collection = new Collection([$bill]);
|
||||
$ranges = [['start' => new Carbon, 'end' => new Carbon]];
|
||||
$this->be($bill->user);
|
||||
|
||||
$bills = $this->mock('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
|
||||
// mock!
|
||||
$bills->shouldReceive('getActiveBills')->andReturn($collection);
|
||||
$bills->shouldReceive('getRanges')->andReturn($ranges);
|
||||
$bills->shouldReceive('getJournalsInRange')->andReturn(new Collection);
|
||||
$accounts->shouldReceive('getCreditCards')->andReturn($ccs);
|
||||
$accounts->shouldReceive('getTransfersInRange')->andReturn(new Collection);
|
||||
Amount::shouldReceive('format')->andReturn('xx');
|
||||
Steam::shouldReceive('balance')->andReturn(0);
|
||||
|
||||
|
||||
$this->call('GET', '/json/box/bills-paid');
|
||||
$this->assertResponseOk();
|
||||
|
||||
}
|
||||
|
||||
public function testBoxBillsUnpaid()
|
||||
{
|
||||
$bill = FactoryMuffin::create('FireflyIII\Models\Bill');
|
||||
$cc = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$ccs = new Collection([$cc]);
|
||||
$collection = new Collection([$bill]);
|
||||
$ranges = [['start' => new Carbon, 'end' => new Carbon]];
|
||||
$this->be($bill->user);
|
||||
|
||||
$bills = $this->mock('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$accounts = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
|
||||
// mock!
|
||||
$bills->shouldReceive('getActiveBills')->andReturn($collection);
|
||||
$bills->shouldReceive('getRanges')->andReturn($ranges);
|
||||
$bills->shouldReceive('getJournalsInRange')->andReturn(new Collection);
|
||||
$bills->shouldReceive('createFakeBill')->andReturn($bill);
|
||||
$accounts->shouldReceive('getCreditCards')->andReturn($ccs);
|
||||
Amount::shouldReceive('format')->andReturn('xx');
|
||||
Steam::shouldReceive('balance')->andReturn(-1);
|
||||
|
||||
$this->call('GET', '/json/box/bills-unpaid');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testBoxIn()
|
||||
{
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Helpers\Report\ReportQueryInterface');
|
||||
$repository->shouldReceive('incomeByPeriod')->andReturn(new Collection);
|
||||
Amount::shouldReceive('format')->andReturn('xx');
|
||||
|
||||
$this->call('GET', '/json/box/in');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testBoxOut()
|
||||
{
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Helpers\Report\ReportQueryInterface');
|
||||
$repository->shouldReceive('journalsByExpenseAccount')->andReturn(new Collection);
|
||||
Amount::shouldReceive('format')->andReturn('xx');
|
||||
|
||||
$this->call('GET', '/json/box/out');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testCategories()
|
||||
{
|
||||
$category = FactoryMuffin::create('FireflyIII\Models\Category');
|
||||
$this->be($category->user);
|
||||
$categories = new Collection([$category]);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$repository->shouldReceive('getCategories')->andReturn($categories);
|
||||
|
||||
$this->call('GET', '/json/categories');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testExpenseAccounts()
|
||||
{
|
||||
$account = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$this->be($account->user);
|
||||
$accounts = new Collection([$account]);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$repository->shouldReceive('getAccounts')->with(['Expense account', 'Beneficiary account'])->andReturn($accounts);
|
||||
|
||||
$this->call('GET', '/json/expense-accounts');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testRevenueAccounts()
|
||||
{
|
||||
$account = FactoryMuffin::create('FireflyIII\Models\Account');
|
||||
$this->be($account->user);
|
||||
$accounts = new Collection([$account]);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$repository->shouldReceive('getAccounts')->with(['Revenue account'])->andReturn($accounts);
|
||||
|
||||
$this->call('GET', '/json/revenue-accounts');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testSetSharedReports()
|
||||
{
|
||||
$pref = FactoryMuffin::create('FireflyIII\Models\Preference');
|
||||
$pref->data = false;
|
||||
$pref->save();
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
Preferences::shouldReceive('get')->withArgs(['showSharedReports', false])->andReturn($pref);
|
||||
Preferences::shouldReceive('set')->withArgs(['showSharedReports', true]);
|
||||
|
||||
$this->call('GET', '/json/show-shared-reports/set');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
|
||||
public function testShowSharedReports()
|
||||
{
|
||||
$pref = FactoryMuffin::create('FireflyIII\Models\Preference');
|
||||
$pref->data = false;
|
||||
$pref->save();
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
Preferences::shouldReceive('get')->withArgs(['showSharedReports', false])->andReturn($pref);
|
||||
|
||||
|
||||
$this->call('GET', '/json/show-shared-reports');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
public function testTransactionJournals()
|
||||
{
|
||||
$journal = FactoryMuffin::create('FireflyIII\Models\TransactionJournal');
|
||||
$type = FactoryMuffin::create('FireflyIII\Models\TransactionType');
|
||||
$collection = new Collection([$journal]);
|
||||
$user = FactoryMuffin::create('FireflyIII\User');
|
||||
$this->be($user);
|
||||
|
||||
$repository = $this->mock('FireflyIII\Repositories\Journal\JournalRepositoryInterface');
|
||||
$repository->shouldReceive('getTransactionType')->with('withdrawal')->andReturn($type);
|
||||
$repository->shouldReceive('getJournalsOfType')->with($type)->andReturn($collection);
|
||||
|
||||
|
||||
$this->call('GET', '/json/transaction-journals/withdrawal');
|
||||
$this->assertResponseOk();
|
||||
}
|
||||
|
||||
}
|
@ -160,10 +160,32 @@ FactoryMuffin::define(
|
||||
]
|
||||
);
|
||||
|
||||
FactoryMuffin::define(
|
||||
'FireflyIII\Models\PiggyBank',
|
||||
[
|
||||
'account_id' => 'factory|FireflyIII\Models\Account',
|
||||
'name' => 'sentence',
|
||||
'targetamount' => 'integer',
|
||||
'startdate' => 'date',
|
||||
'targetdate' => 'date',
|
||||
'reminder_skip' => 0,
|
||||
'remind_me' => 0,
|
||||
'order' => 0,
|
||||
]
|
||||
);
|
||||
|
||||
FactoryMuffin::define(
|
||||
'FireflyIII\Models\TransactionType',
|
||||
[
|
||||
'type' => 'word',
|
||||
'type' => function () {
|
||||
$types = ['Withdrawal', 'Deposit', 'Transfer'];
|
||||
$count = DB::table('transaction_types')->count();
|
||||
if ($count < 3) {
|
||||
return $types[$count];
|
||||
} else {
|
||||
return RandomString::generateRandomString(10);
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user