diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index a4862219a6..7545517016 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -13,8 +13,9 @@ use Preferences; use Redirect; use Response; use Session; -use View; use URL; +use View; + /** * Class BudgetController * @@ -88,7 +89,6 @@ class BudgetController extends Controller $repository->destroy($budget); - Session::flash('success', 'The budget "' . e($name) . '" was deleted.'); return Redirect::to(Session::get('budgets.delete.url')); @@ -118,8 +118,8 @@ class BudgetController extends Controller */ public function index(BudgetRepositoryInterface $repository) { - $budgets = Auth::user()->budgets()->where('active', 1)->get(); - $inactive = Auth::user()->budgets()->where('active', 0)->get(); + $budgets = $repository->getActiveBudgets(); + $inactive = $repository->getInactiveBudgets(); /** * Do some cleanup: @@ -127,19 +127,18 @@ class BudgetController extends Controller $repository->cleanupBudgets(); - // loop the budgets: $budgets->each( function (Budget $budget) use ($repository) { $date = Session::get('start', Carbon::now()->startOfMonth()); $budget->spent = $repository->spentInMonth($budget, $date); - $budget->currentRep = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); + $budget->currentRep = $repository->getCurrentRepetition($budget, $date); } ); - $date = Session::get('start', Carbon::now()->startOfMonth())->format('FY'); + $dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY'); $spent = $budgets->sum('spent'); - $amount = Preferences::get('budgetIncomeTotal' . $date, 1000)->data; + $amount = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data; $overspent = $spent > $amount; $spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100); $budgetMax = Preferences::get('budgetMaximum', 1000); @@ -151,20 +150,11 @@ class BudgetController extends Controller /** * @return \Illuminate\View\View */ - public function noBudget() + public function noBudget(BudgetRepositoryInterface $repository) { - $start = \Session::get('start', Carbon::now()->startOfMonth()); - $end = \Session::get('end', Carbon::now()->startOfMonth()); - $list = Auth::user() - ->transactionjournals() - ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->whereNull('budget_transaction_journal.id') - ->before($end) - ->after($start) - ->orderBy('transaction_journals.date', 'DESC') - ->orderBy('transaction_journals.order', 'ASC') - ->orderBy('transaction_journals.id', 'DESC') - ->get(['transaction_journals.*']); + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->startOfMonth()); + $list = $repository->getWithoutBudget($start, $end); $subTitle = 'Transactions without a budget in ' . $start->format('F Y'); return view('budgets.noBudget', compact('list', 'subTitle')); @@ -182,6 +172,27 @@ class BudgetController extends Controller return Redirect::route('budgets.index'); } + /** + * + * @param Budget $budget + * @param LimitRepetition $repetition + * + * @return \Illuminate\View\View + */ + public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository) + { + if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) { + return view('error')->with('message', 'Invalid selection.'); + } + + $hideBudget = true; // used in transaction list. + $journals = $repository->getJournals($budget, $repetition); + $limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $repository->getBudgetLimits($budget); + $subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name); + + return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget')); + } + /** * @param BudgetFormRequest $request * @param BudgetRepositoryInterface $repository @@ -201,6 +212,7 @@ class BudgetController extends Controller if (intval(Input::get('create_another')) === 1) { // set value so create routine will not overwrite URL: Session::put('budgets.create.fromStore', true); + return Redirect::route('budgets.create')->withInput(); } @@ -209,27 +221,6 @@ class BudgetController extends Controller } - /** - * - * @param Budget $budget - * @param LimitRepetition $repetition - * - * @return \Illuminate\View\View - */ - public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository) - { - if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) { - return view('error')->with('message', 'Invalid selection.'); - } - - $hideBudget = true; // used in transaction list. - $journals = $repository->getJournals($budget, $repetition); - $limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get(); - $subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name); - - return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget')); - } - /** * @param Budget $budget * @param BudgetFormRequest $request @@ -251,6 +242,7 @@ class BudgetController extends Controller if (intval(Input::get('return_to_edit')) === 1) { // set value so edit routine will not overwrite URL: Session::put('budgets.edit.fromUpdate', true); + return Redirect::route('budgets.edit', $budget->id)->withInput(['return_to_edit' => 1]); } diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index bfd2655e46..5d614286bd 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -2,11 +2,13 @@ namespace FireflyIII\Repositories\Budget; +use Auth; use Carbon\Carbon; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\LimitRepetition; use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; /** * Class BudgetRepository @@ -37,7 +39,7 @@ class BudgetRepository implements BudgetRepositoryInterface } // delete limits with amount 0: - BudgetLimit::where('amount',0)->delete(); + BudgetLimit::where('amount', 0)->delete(); } @@ -53,6 +55,33 @@ class BudgetRepository implements BudgetRepositoryInterface return true; } + /** + * @return Collection + */ + public function getActiveBudgets() + { + return Auth::user()->budgets()->where('active', 1)->get(); + } + + /** + * @param Budget $budget + * @param Carbon $date + * + * @return LimitRepetition|null + */ + public function getCurrentRepetition(Budget $budget, Carbon $date) + { + return $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); + } + + /** + * @return Collection + */ + public function getInactiveBudgets() + { + return Auth::user()->budgets()->where('active', 1)->get(); + } + /** * Returns all the transaction journals for a limit, possibly limited by a limit repetition. * @@ -86,6 +115,26 @@ class BudgetRepository implements BudgetRepositoryInterface return new LengthAwarePaginator($set, $count, $take, $offset); } + /** + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getWithoutBudget(Carbon $start, Carbon $end) + { + return Auth::user() + ->transactionjournals() + ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->whereNull('budget_transaction_journal.id') + ->before($end) + ->after($start) + ->orderBy('transaction_journals.date', 'DESC') + ->orderBy('transaction_journals.order', 'ASC') + ->orderBy('transaction_journals.id', 'DESC') + ->get(['transaction_journals.*']); + } + /** * @param Budget $budget * @param Carbon $date @@ -175,4 +224,14 @@ class BudgetRepository implements BudgetRepositoryInterface } + + /** + * @param Budget $budget + * + * @return Collection + */ + public function getBudgetLimits(Budget $budget) + { + return $budget->budgetLimits()->orderBy('startdate', 'DESC')->get(); + } } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index 9b5eef9229..38cdc43532 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -5,6 +5,7 @@ namespace FireflyIII\Repositories\Budget; use Carbon\Carbon; use FireflyIII\Models\Budget; use FireflyIII\Models\LimitRepetition; +use Illuminate\Support\Collection; /** * Interface BudgetRepositoryInterface @@ -20,6 +21,16 @@ interface BudgetRepositoryInterface */ public function destroy(Budget $budget); + /** + * @return Collection + */ + public function getActiveBudgets(); + + /** + * @return Collection + */ + public function getInactiveBudgets(); + /** * @return void */ @@ -33,6 +44,29 @@ interface BudgetRepositoryInterface */ public function spentInMonth(Budget $budget, Carbon $date); + /** + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getWithoutBudget(Carbon $start, Carbon $end); + + /** + * @param Budget $budget + * + * @return Collection + */ + public function getBudgetLimits(Budget $budget); + + /** + * @param Budget $budget + * @param Carbon $date + * + * @return LimitRepetition|null + */ + public function getCurrentRepetition(Budget $budget, Carbon $date); + /** * @param Budget $budget * @param Carbon $date diff --git a/pu.sh b/pu.sh index fac111b016..a532d9ecf0 100755 --- a/pu.sh +++ b/pu.sh @@ -7,7 +7,15 @@ cp .env .env.backup cp .env.testing .env # test! -phpunit --verbose +if [ -z "$1" ] +then + phpunit --verbose +fi + +if [ ! -z "$1" ] +then + phpunit --verbose tests/controllers/$1.php +fi # restore .env file mv .env.backup .env diff --git a/tests/controllers/AccountControllerTest.php b/tests/controllers/AccountControllerTest.php index ea42cd83c3..be21d77d87 100644 --- a/tests/controllers/AccountControllerTest.php +++ b/tests/controllers/AccountControllerTest.php @@ -8,7 +8,7 @@ use Illuminate\Support\Collection; use League\FactoryMuffin\Facade as FactoryMuffin; /** - * Generated by PHPUnit_SkeletonGenerator on 2015-03-08 at 20:05:14. + * Class AccountControllerTest */ class AccountControllerTest extends TestCase { diff --git a/tests/controllers/BudgetControllerTest.php b/tests/controllers/BudgetControllerTest.php new file mode 100644 index 0000000000..935f491544 --- /dev/null +++ b/tests/controllers/BudgetControllerTest.php @@ -0,0 +1,179 @@ +mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $limitRepetition = FactoryMuffin::create('FireflyIII\Models\LimitRepetition'); + $budget = $limitRepetition->budgetlimit->budget; + $this->be($budget->user); + $today = new Carbon; + + $this->session(['start' => $today]); + $repository->shouldReceive('updateLimitAmount')->once()->andReturn($limitRepetition); + $this->call('POST', '/budgets/amount/' . $budget->id, ['amount' => 100, '_token' => 'replaceme']); + $this->assertResponseOk(); + + } + + public function testCreate() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $this->be($budget->user); + $this->call('GET', '/budgets/create'); + $this->assertResponseOk(); + $this->assertViewHas('subTitle', 'Create a new budget'); + } + + public function testDelete() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $this->be($budget->user); + $this->call('GET', '/budgets/delete/' . $budget->id); + + $this->assertResponseOk(); + $this->assertViewHas('subTitle', 'Delete budget' . e($budget->name) . '"'); + $this->assertViewHas('budget'); + $this->assertSessionHas('budgets.delete.url'); + } + + public function testDestroy() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $this->be($budget->user); + + $this->assertCount(1, DB::table('budgets')->where('id', $budget->id)->get()); + + $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() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $this->be($budget->user); + + $this->call('GET', '/budgets/edit/' . $budget->id); + + $this->assertResponseOk(); + $this->assertViewHas('subTitle', 'Edit budget "' . e($budget->name) . '"'); + $this->assertViewHas('budget'); + $this->assertSessionHas('budgets.edit.url'); + } + + public function testIndex() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $this->be($budget->user); + $collection = new Collection; + $collection->push($budget); + $repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + + $repository->shouldReceive('getActiveBudgets')->once()->andReturn($collection); + $repository->shouldReceive('getInactiveBudgets')->once()->andReturn($collection); + $repository->shouldReceive('cleanupBudgets')->once(); + $repository->shouldReceive('spentInMonth')->once(); + $repository->shouldReceive('getCurrentRepetition')->once(); + Amount::shouldReceive('getCurrencySymbol')->andReturn('x'); + Amount::shouldReceive('format')->andReturn('x'); + $this->call('GET', '/budgets'); + + $this->assertResponseOk(); + $this->assertViewHas('budgets'); + $this->assertViewHas('inactive'); + $this->assertViewHas('inactive'); + + } + + public function testNoBudget() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $this->be($budget->user); + $repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $repository->shouldReceive('getWithoutBudget')->andReturn(new Collection); + + $this->call('GET', '/budgets/list/noBudget'); + $this->assertResponseOk(); + $this->assertViewHas('list'); + $this->assertViewHas('subTitle'); + } + + public function testPostUpdateIncome() + { + $date = Carbon::now()->startOfMonth()->format('FY'); + Preferences::shouldReceive('set')->once()->withArgs(['budgetIncomeTotal' . $date, 1001]); + + $this->call('POST', '/budgets/income', ['_token' => 'replaceme', 'amount' => 1001]); + $this->assertResponseStatus(302); + } + + public function testShow() + { + $budget = FactoryMuffin::create('FireflyIII\Models\Budget'); + $repository = $this->mock('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $this->be($budget->user); + + Amount::shouldReceive('getCurrencyCode')->andReturn('x'); + Amount::shouldReceive('format')->andReturn('x'); + $repository->shouldReceive('getJournals')->andReturn(new Collection); + $repository->shouldReceive('getBudgetLimits')->andReturn(new Collection); + + + $this->call('GET', '/budgets/show/' . $budget->id); + $this->assertResponseOk(); + + } + + public function testStore() + { + $this->markTestIncomplete(); + } + + public function testUpdate() + { + $this->markTestIncomplete(); + } + + public function testUpdateIncome() + { + $this->markTestIncomplete(); + } +} \ No newline at end of file diff --git a/tests/factories/all.php b/tests/factories/all.php index 44a7ca5469..99572f38e1 100644 --- a/tests/factories/all.php +++ b/tests/factories/all.php @@ -38,6 +38,36 @@ FactoryMuffin::define( ] ); +FactoryMuffin::define( + 'FireflyIII\Models\Budget', [ + 'user_id' => 'factory|FireflyIII\User', + 'name' => 'word', + 'active' => 'boolean', + 'encrypted' => 1, + ] +); + +FactoryMuffin::define( + 'FireflyIII\Models\LimitRepetition', [ + 'budget_limit_id' => 'factory|FireflyIII\Models\BudgetLimit', + 'startdate' => 'date', + 'enddate' => 'date', + 'amount' => 'integer', + ] +); + +FactoryMuffin::define( + 'FireflyIII\Models\BudgetLimit', [ + 'budget_id' => 'factory|FireflyIII\Models\Budget', + 'startdate' => 'date', + 'amount' => 'integer', + 'repeats' => 'false', + 'repeat_freq' => 'monthly', + + ] +); + + FactoryMuffin::define( 'FireflyIII\Models\Preference', [ 'name' => 'word', @@ -51,6 +81,7 @@ FactoryMuffin::define( 'type' => function () { $types = ['Expense account', 'Revenue account', 'Asset account']; $count = DB::table('account_types')->count(); + return $types[$count]; }, 'editable' => 1,