Compare commits

...

28 Commits
3.0.1 ... 3.0.2

Author SHA1 Message Date
James Cole
b8e07ac38e Removed another word wrap. 2014-09-09 10:46:35 +02:00
James Cole
c7273e4b60 Removed a chart wrap. 2014-09-09 10:45:51 +02:00
James Cole
33d4fd4af0 Small fix for the budget overview. 2014-09-09 10:43:12 +02:00
James Cole
71b11e26d2 Cleaned up the chart controller. 2014-09-09 10:42:58 +02:00
James Cole
77f4111b09 Fixed some bugs in the recurring transactions trigger 2014-09-09 07:10:37 +02:00
James Cole
9965297f36 Cleaning up the chart controller. 2014-09-09 07:10:16 +02:00
James Cole
5ca466a826 Update view. 2014-09-08 10:38:39 +02:00
James Cole
90f417facc Update model. 2014-09-08 10:38:26 +02:00
James Cole
eacbd038b7 Updated migration to include recurring transactions. 2014-09-08 10:38:14 +02:00
James Cole
5446e85424 New trigger for new journals. 2014-09-08 10:37:55 +02:00
James Cole
77b4942691 Uniform query. 2014-09-08 10:37:31 +02:00
James Cole
824cf71e0b Some re-alignment and catches for NULLs 2014-09-08 10:37:14 +02:00
James Cole
239bbd30c0 Fire some events. 2014-09-08 10:36:32 +02:00
James Cole
6f6b653d54 Removed some logging. 2014-09-08 10:36:19 +02:00
James Cole
e4155ce735 Moved a migration because of reasons. 2014-09-08 10:36:06 +02:00
James Cole
7eaf307834 Some code cleanup. 2014-09-04 09:02:54 +02:00
James Cole
7db7950415 Updated read-me. 2014-09-04 08:32:37 +02:00
James Cole
fcc184cd2a Removed ALL tests. Yes, I know. 2014-09-04 08:32:13 +02:00
James Cole
6423feff3a Cleaned up some models and controllers. 2014-09-04 08:31:45 +02:00
James Cole
e97da25d5a Cleaned up build files. 2014-09-04 08:31:07 +02:00
James Cole
f49a37a38e Removed unused classes. 2014-09-04 08:30:17 +02:00
James Cole
07e6b33095 Some tests fixed. But messy! [skip ci] 2014-09-03 21:12:51 +02:00
James Cole
9136b50e3c Slowly working my way "down" the list of controllers to fix and enhance. 2014-09-03 16:50:53 +02:00
James Cole
c3fd5c7136 Some new stuff that really doesn't belong here. I'm not good at this. 2014-09-03 07:11:35 +02:00
James Cole
98612dd253 Last changes to make the import routine work. 2014-09-02 19:12:57 +02:00
James Cole
4d7f5238dd Moar updates. 2014-09-02 17:27:28 +02:00
James Cole
f472a01a80 First attempt, trying to build an import stuff routine. 2014-09-02 08:58:56 +02:00
James Cole
420b5790e3 New ignore files [skip ci] 2014-08-31 15:26:51 +02:00
112 changed files with 2701 additions and 4663 deletions

3
.gitignore vendored
View File

@@ -11,4 +11,5 @@ tests/_output/*
_ide_helper.php
/build/logs/clover.xml
index.html*
app/storage/firefly-export*
app/storage/firefly-export*
.vagrant

View File

@@ -2,7 +2,6 @@ firefly-iii
===========
[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=master)](https://travis-ci.org/JC5/firefly-iii)
[![Coverage Status](https://coveralls.io/repos/JC5/firefly-iii/badge.png?branch=master)](https://coveralls.io/r/JC5/firefly-iii?branch=master)
![Still maintained?](http://stillmaintained.com/JC5/firefly-iii.png)
[![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)

View File

@@ -26,6 +26,9 @@ $(function () {
str += '<span style="color:' + colour + '">' + point.series.name + '</span>: € ' + Highcharts.numberFormat(point.y, 2) + '<br />';
}
if (x == 1) {
str += '<span style="color:' + colour + '">' + point.series.name + '</span>: € ' + Highcharts.numberFormat(point.y, 2) + '<br />';
}
if (x == 2) {
str += '<span style="color:' + colour + '">' + point.series.name + '</span>: ' + Highcharts.numberFormat(point.y, 1) + '%<br />';
}
}

View File

@@ -1,2 +1,3 @@
local/
laptop/
laptop/
vagrant/

View File

@@ -8,6 +8,8 @@ use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class AccountController extends \BaseController
{
@@ -66,7 +68,8 @@ class AccountController extends \BaseController
public function edit(Account $account)
{
$openingBalance = $this->_accounts->openingBalanceTransaction($account);
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance)->with('title','Edit account "'.$account->name.'"');
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance)
->with('title', 'Edit account "' . $account->name . '"');
}
/**
@@ -90,7 +93,7 @@ class AccountController extends \BaseController
}
}
return View::make('accounts.index')->with('accounts', $set)->with('title','All your accounts');
return View::make('accounts.index')->with('accounts', $set)->with('title', 'All your accounts');
}
/**

View File

@@ -1,5 +1,7 @@
<?php
use \Illuminate\Routing\Controller;
/**
* Class BaseController
*/

View File

@@ -6,6 +6,9 @@ use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
/**
* Class BudgetController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*
*/
class BudgetController extends BaseController
{
@@ -14,12 +17,12 @@ class BudgetController extends BaseController
protected $_repository;
/**
* @param BI $budgets
* @param BI $budgets
* @param BRI $repository
*/
public function __construct(BI $budgets, BRI $repository)
{
$this->_budgets = $budgets;
$this->_budgets = $budgets;
$this->_repository = $repository;
}
@@ -30,7 +33,7 @@ class BudgetController extends BaseController
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('budgets.create')->with('periods', $periods);
return View::make('budgets.create')->with('periods', $periods)->with('title', 'Create a new budget');
}
/**
@@ -40,7 +43,8 @@ class BudgetController extends BaseController
*/
public function delete(Budget $budget)
{
return View::make('budgets.delete')->with('budget', $budget);
return View::make('budgets.delete')->with('budget', $budget)
->with('title', 'Delete budget "' . $budget->name . '"');
}
/**
@@ -50,20 +54,16 @@ class BudgetController extends BaseController
*/
public function destroy(Budget $budget)
{
// remove budget
Event::fire('budgets.destroy', [$budget]); // just before deletion.
$result = $this->_repository->destroy($budget);
if ($result === true) {
Session::flash('success', 'The budget was deleted.');
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
} else {
return Redirect::route('budgets.index.budget');
}
} else {
Session::flash('error', 'Could not delete the budget. Check the logs to be sure.');
}
$this->_repository->destroy($budget);
Session::flash('success', 'The budget was deleted.');
return Redirect::route('budgets.index');
// redirect:
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
}
return Redirect::route('budgets.index.budget');
}
@@ -74,7 +74,8 @@ class BudgetController extends BaseController
*/
public function edit(Budget $budget)
{
return View::make('budgets.edit')->with('budget', $budget);
return View::make('budgets.edit')->with('budget', $budget)
->with('title', 'Edit budget "' . $budget->name . '"');
}
@@ -84,62 +85,71 @@ class BudgetController extends BaseController
public function indexByBudget()
{
$budgets = $this->_repository->get();
$today = new Carbon;
return View::make('budgets.indexByBudget')->with('budgets', $budgets)->with('today', $today);
return View::make('budgets.indexByBudget')->with('budgets', $budgets)->with('today', new Carbon)
->with('title', 'All your budgets grouped by budget');
}
/**
* @return $this|\Illuminate\View\View
* @throws Firefly\Exception\FireflyException
* @return $this
*/
public function indexByDate()
{
// get a list of dates by getting all repetitions:
$set = $this->_repository->get();
$set = $this->_repository->get();
$budgets = $this->_budgets->organizeByDate($set);
return View::make('budgets.indexByDate')->with('budgets', $budgets);
return View::make('budgets.indexByDate')->with('budgets', $budgets)
->with('title', 'All your budgets grouped by date');
}
/**
* Three use cases for this view:
*
* - Show everything.
* - Show a specific repetition.
* - Show everything shows NO repetition.
*
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return int
*/
public function show(Budget $budget)
public function show(Budget $budget, \LimitRepetition $repetition = null)
{
/**
* Use the
*/
$useSessionDates = Input::get('useSession') == 'true' ? true : false;
$filters = [];
if (!is_null(Input::get('rep'))) {
$repetitionId = intval(Input::get('rep'));
$repetitions = $this->_budgets->organizeRepetition($repetitionId);
$filters[] = $repetitions[0]['limit'];
$filters[] = $repetitions[0]['limitrepetition'];
} else {
if (Input::get('noenvelope') == 'true') {
$repetitions = $this->_budgets->outsideRepetitions($budget);
$filters[] = 'no_envelope';
} else {
// grab all limit repetitions, order them, show them:
$repetitions = $this->_budgets->organizeRepetitions($budget, $useSessionDates);
}
$view = null;
$title = null;
\Log::debug('Is envelope true? ' . (Input::get('noenvelope') == 'true'));
switch (true) {
case (!is_null($repetition)):
$data = $this->_budgets->organizeRepetition($repetition);
$view = 1;
$title = $budget->name . ', ' . $repetition->periodShow() . ', ' . mf($repetition->limit->amount,
false);
break;
case (Input::get('noenvelope') == 'true'):
$data = $this->_budgets->outsideRepetitions($budget);
$view = 2;
$title = $budget->name . ', transactions outside an envelope';
break;
default:
$data = $this->_budgets->organizeRepetitions($budget, $useSessionDates);
$view = $useSessionDates ? 3 : 4;
$title = $useSessionDates ? $budget->name . ' in session period' : $budget->name;
break;
}
return View::make('budgets.show')->with('budget', $budget)->with('repetitions', $repetitions)->with(
'filters', $filters
)->with('highlight', Input::get('highlight'))->with('useSessionDates', $useSessionDates);
return View::make('budgets.show')
->with('budget', $budget)
->with('repetitions', $data)
->with('view', $view)
->with('highlight', Input::get('highlight'))
->with('useSessionDates', $useSessionDates)
->with('title', $title);
}
/**

View File

@@ -13,12 +13,12 @@ class CategoryController extends BaseController
/**
* @param CRI $repository
* @param CI $category
* @param CI $category
*/
public function __construct(CRI $repository, CI $category)
{
$this->_repository = $repository;
$this->_category = $category;
$this->_category = $category;
}
/**
@@ -26,7 +26,7 @@ class CategoryController extends BaseController
*/
public function create()
{
return View::make('categories.create');
return View::make('categories.create')->with('title', 'Create a new category');
}
/**
@@ -36,7 +36,8 @@ class CategoryController extends BaseController
*/
public function delete(Category $category)
{
return View::make('categories.delete')->with('category', $category);
return View::make('categories.delete')->with('category', $category)
->with('title', 'Delete category "' . $category->name . '"');
}
/**
@@ -46,13 +47,8 @@ class CategoryController extends BaseController
*/
public function destroy(Category $category)
{
$result = $this->_repository->destroy($category);
if ($result === true) {
Session::flash('success', 'The category was deleted.');
} else {
Session::flash('error', 'Could not delete the category. Check the logs to be sure.');
}
$this->_repository->destroy($category);
Session::flash('success', 'The category was deleted.');
return Redirect::route('categories.index');
}
@@ -63,7 +59,8 @@ class CategoryController extends BaseController
*/
public function edit(Category $category)
{
return View::make('categories.edit')->with('category', $category);
return View::make('categories.edit')->with('category', $category)
->with('title', 'Edit category "' . $category->name . '"');
}
/**
@@ -73,7 +70,8 @@ class CategoryController extends BaseController
{
$categories = $this->_repository->get();
return View::make('categories.index')->with('categories', $categories);
return View::make('categories.index')->with('categories', $categories)
->with('title', 'All your categories');
}
/**
@@ -84,14 +82,14 @@ class CategoryController extends BaseController
public function show(Category $category)
{
$start = \Session::get('start');
$end = \Session::get('end');
$end = \Session::get('end');
$journals = $this->_category->journalsInRange($category, $start, $end);
return View::make('categories.show')->with('category', $category)->with('journals', $journals)->with(
'highlight', Input::get('highlight')
);
'highlight', Input::get('highlight')
)->with('title', 'Overview for category "'.$category->name.'"');;
}
/**

View File

@@ -20,42 +20,35 @@ class ChartController extends BaseController
*/
public function __construct(ChartInterface $chart, AccountRepositoryInterface $accounts)
{
$this->_chart = $chart;
$this->_chart = $chart;
$this->_accounts = $accounts;
}
/**
* This method takes a budget, all limits and all their repetitions and displays three numbers per repetition:
* the amount of money in the repetition (represented as "an envelope"), the amount spent and the spent percentage.
*
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetDefault(\Budget $budget)
{
$expense = [];
$left = [];
$expense = [];
$left = [];
$envelope = [];
// get all limit repetitions for this budget.
/** @var \Limit $limit */
foreach ($budget->limits as $limit) {
/** @var \LimitRepetition $rep */
foreach ($limit->limitrepetitions as $rep) {
$spentInRep = \Transaction::
leftJoin(
'transaction_journals', 'transaction_journals.id', '=',
'transactions.transaction_journal_id'
)
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id',
'=',
'transaction_journals.id'
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
'transaction_journals.date', '>=', $rep->startdate->format('Y-m-d')
)->where('transaction_journals.date', '<=', $rep->enddate->format('Y-m-d'))->where(
'amount', '>', 0
)->sum('amount');
$pct = round(($spentInRep / $limit->amount) * 100, 2);
$name = $rep->periodShow();
$expense[] = [$name, floatval($spentInRep)];
$left[] = [$name, $pct];
// get the amount of money spent in this period on this budget.
$spentInRep = $rep->amount - $rep->left();
$pct = round((floatval($spentInRep) / floatval($limit->amount)) * 100, 2);
$name = $rep->periodShow();
$envelope[] = [$name, floatval($limit->amount)];
$expense[] = [$name, floatval($spentInRep)];
$left[] = [$name, $pct];
}
}
@@ -63,6 +56,12 @@ class ChartController extends BaseController
'chart_title' => 'Overview for budget ' . $budget->name,
'subtitle' => 'All envelopes',
'series' => [
[
'type' => 'line',
'yAxis' => 1,
'name' => 'Amount in envelope',
'data' => $envelope
],
[
'type' => 'column',
'name' => 'Expenses in envelope',
@@ -75,6 +74,7 @@ class ChartController extends BaseController
'data' => $left
]
]
];
@@ -82,29 +82,27 @@ class ChartController extends BaseController
}
/**
* This method takes a single limit repetition (so a single "envelope") and displays the amount of money spent
* per day and subsequently how much money is left.
*
* @param LimitRepetition $rep
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetLimit(\LimitRepetition $rep)
{
$budget = $rep->limit->budget;
$current = clone $rep->startdate;
$expense = [];
$leftInLimit = [];
$budget = $rep->limit->budget;
$current = clone $rep->startdate;
$expense = [];
$leftInLimit = [];
$currentLeftInLimit = floatval($rep->limit->amount);
while ($current <= $rep->enddate) {
$spent = \Transaction::
leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
'transaction_journals.id'
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
'transaction_journals.date', $current->format('Y-m-d')
)->where('amount', '>', 0)->sum('amount');
$spent = floatval($spent) == 0 ? null : floatval($spent);
$entry = [$current->timestamp * 1000, $spent];
$expense[] = $entry;
$spent = $this->_chart->spentOnDay($budget, $current);
$spent = floatval($spent) == 0 ? null : floatval($spent);
$entry = [$current->timestamp * 1000, $spent];
$expense[] = $entry;
$currentLeftInLimit = $currentLeftInLimit - $spent;
$leftInLimit[] = [$current->timestamp * 1000, $currentLeftInLimit];
$leftInLimit[] = [$current->timestamp * 1000, $currentLeftInLimit];
$current->addDay();
}
@@ -132,53 +130,44 @@ class ChartController extends BaseController
}
/**
* This method takes a budget and gets all transactions in it which haven't got an envelope (limit).
*
* Usually this means that very old and unorganized or very NEW transactions get displayed; there was never an
* envelope or it hasn't been created (yet).
*
*
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetNoLimits(\Budget $budget)
{
$inRepetitions = [];
foreach ($budget->limits as $limit) {
foreach ($limit->limitrepetitions as $repetition) {
$set = $budget->transactionjournals()->leftJoin(
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
)->where('transaction_types.type', 'Withdrawal')->where(
'date', '>=', $repetition->startdate->format('Y-m-d')
)->where('date', '<=', $repetition->enddate->format('Y-m-d'))->orderBy('date', 'DESC')->get(
['transaction_journals.id']
);
foreach ($set as $item) {
$inRepetitions[] = $item->id;
}
}
/*
* We can go about this two ways. Either we find all transactions which definitely are IN an envelope
* and exclude them or we search for transactions outside of the range of any of the envelopes we have.
*
* Since either is shitty we go with the first one because it's easier to build.
*/
$inRepetitions = $this->_chart->allJournalsInBudgetEnvelope($budget);
}
$query = $budget->transactionjournals()->whereNotIn(
'transaction_journals.id', $inRepetitions
)->orderBy('date', 'DESC')->orderBy(
'transaction_journals.id', 'DESC'
);
/*
* With this set of id's, we can search for all journals NOT in that set.
* BUT they have to be in the budget (duh).
*/
$set = $this->_chart->journalsNotInSet($budget, $inRepetitions);
/*
* Next step: get all transactions for those journals.
*/
$transactions = $this->_chart->transactionsByJournals($set);
$result = $query->get(['transaction_journals.id']);
$set = [];
foreach ($result as $entry) {
$set[] = $entry->id;
}
// all transactions for these journals, grouped by date and SUM
$transactions = \Transaction::whereIn('transaction_journal_id', $set)->leftJoin(
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
)
->groupBy('transaction_journals.date')->where('amount', '>', 0)->get(
['transaction_journals.date', DB::Raw('SUM(`amount`) as `aggregate`')]
);
// this set builds the chart:
/*
* this set builds the chart:
*/
$expense = [];
foreach ($transactions as $t) {
$date = new Carbon($t->date);
$date = new Carbon($t->date);
$expense[] = [$date->timestamp * 1000, floatval($t->aggregate)];
}
$return = [
@@ -186,126 +175,104 @@ class ChartController extends BaseController
'subtitle' => 'Not organized by an envelope',
'series' => [
[
'type' => 'spline',
'type' => 'column',
'name' => 'Expenses per day',
'data' => $expense
]
]
];
return Response::json($return);
}
/**
* This method gets all transactions within a budget within the period set by the current session
* start and end date. It also includes any envelopes which might exist within this period.
*
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetSession(\Budget $budget)
{
$expense = [];
$repetitionSeries = [];
$current = clone Session::get('start');
$end = clone Session::get('end');
while ($current <= $end) {
$spent = \Transaction::
leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
'transaction_journals.id'
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
'transaction_journals.date', $current->format('Y-m-d')
)->where('amount', '>', 0)->sum('amount');
$spent = floatval($spent) == 0 ? null : floatval($spent);
if (!is_null($spent)) {
$expense[] = [$current->timestamp * 1000, $spent];
}
$series = [];
$end = clone Session::get('end');
$start = clone Session::get('start');
/*
* Expenses per day in the session's period. That's easy.
*/
$expense = [];
$current = clone Session::get('start');
while ($current <= $end) {
$spent = $this->_chart->spentOnDay($budget, $current);
$spent = floatval($spent) == 0 ? null : floatval($spent);
$expense[] = [$current->timestamp * 1000, $spent];
$current->addDay();
}
// find all limit repetitions (for this budget) between start and end.
$start = clone Session::get('start');
$repetitionSeries[] = [
$series[] = [
'type' => 'column',
'name' => 'Expenses per day',
'data' => $expense
];
unset($expense, $spent, $current);
/*
* Find all limit repetitions (for this budget) between start and end. This is
* quite a complex query.
*/
$reps = $this->_chart->limitsInRange($budget, $start, $end);
/** @var \Limit $limit */
foreach ($budget->limits as $limit) {
$reps = $limit->limitrepetitions()->where(
function ($q) use ($start, $end) {
// startdate is between range
$q->where(
function ($q) use ($start, $end) {
$q->where('startdate', '>=', $start->format('Y-m-d'));
$q->where('startdate', '<=', $end->format('Y-m-d'));
}
/*
* For each limitrepetition we create a serie that contains the amount left in
* the limitrepetition for its entire date-range. Entries are only actually included when they
* fall into the charts date range.
*
* So example: we have a session date from Jan 15 to Jan 30. The limitrepetition starts at 1 Jan until 1 Feb.
*
* We loop from 1 Jan to 1 Feb but only include Jan 15 / Jan 30. But we do keep count of the amount outside
* of these dates because otherwise the line might be wrong.
*/
/** @var \LimitRepetition $repetition */
foreach ($reps as $repetition) {
$limitAmount = $repetition->limit->amount;
// create a serie for the repetition.
$currentSerie = [
'type' => 'spline',
'id' => 'rep-' . $repetition->id,
'yAxis' => 1,
'name' => 'Envelope #'.$repetition->id.' in ' . $repetition->periodShow(),
'data' => []
];
$current = clone $repetition->startdate;
while ($current <= $repetition->enddate) {
if ($current >= $start && $current <= $end) {
// spent on limit:
$spentSoFar = $this->_chart->spentOnLimitRepetitionBetweenDates(
$repetition, $repetition->startdate, $current
);
$leftInLimit = floatval($limitAmount) - floatval($spentSoFar);
// or enddate is between range.
$q->orWhere(
function ($q) use ($start, $end) {
$q->where('enddate', '>=', $start->format('Y-m-d'));
$q->where('enddate', '<=', $end->format('Y-m-d'));
}
);
$currentSerie['data'][] = [$current->timestamp * 1000, $leftInLimit];
}
)
->get();
$currentLeftInLimit = floatval($limit->amount);
/** @var \LimitRepetition $repetition */
foreach ($reps as $repetition) {
// create a serie for the repetition.
$currentSerie = [
'type' => 'spline',
'id' => 'rep-' . $repetition->id,
'yAxis' => 1,
'name' => 'Envelope in ' . $repetition->periodShow(),
'data' => []
];
$current = clone $repetition->startdate;
while ($current <= $repetition->enddate) {
if ($current >= Session::get('start') && $current <= Session::get('end')) {
// spent on limit:
$spentSoFar = \Transaction::
leftJoin(
'transaction_journals', 'transaction_journals.id', '=',
'transactions.transaction_journal_id'
)
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id',
'=',
'transaction_journals.id'
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
'transaction_journals.date', '>=', $repetition->startdate->format('Y-m-d')
)->where('transaction_journals.date', '<=', $current->format('Y-m-d'))->where(
'amount', '>', 0
)->sum('amount');
$spent = floatval($spent) == 0 ? null : floatval($spent);
$currentLeftInLimit = floatval($limit->amount) - floatval($spentSoFar);
$currentSerie['data'][] = [$current->timestamp * 1000, $currentLeftInLimit];
}
$current->addDay();
}
// do something here.
$repetitionSeries[] = $currentSerie;
$current->addDay();
}
// do something here.
$series[] = $currentSerie;
}
$return = [
'chart_title' => 'Overview for budget ' . $budget->name,
'subtitle' =>
'Between ' . Session::get('start')->format('M jS, Y') . ' and ' . Session::get('end')->format(
'M jS, Y'
),
'series' => $repetitionSeries
'series' => $series
];
return Response::json($return);
@@ -320,11 +287,11 @@ class ChartController extends BaseController
public function categoryShowChart(Category $category)
{
$start = Session::get('start');
$end = Session::get('end');
$end = Session::get('end');
$range = Session::get('range');
$serie = $this->_chart->categoryShowChart($category, $range, $start, $end);
$data = [
$data = [
'chart_title' => $category->name,
'subtitle' => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>',
'series' => $serie
@@ -344,23 +311,23 @@ class ChartController extends BaseController
{
// get preferences and accounts (if necessary):
$start = Session::get('start');
$end = Session::get('end');
$end = Session::get('end');
if (is_null($account)) {
// get, depending on preferences:
/** @var \Firefly\Helper\Preferences\PreferencesHelperInterface $prefs */
$prefs = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
$pref = $prefs->get('frontpageAccounts', []);
$pref = $prefs->get('frontpageAccounts', []);
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $acct */
$acct = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$acct = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$accounts = $acct->getByIds($pref->data);
} else {
$accounts = [$account];
}
// loop and get array data.
$url = count($accounts) == 1 && is_array($accounts)
$url = count($accounts) == 1 && is_array($accounts)
? '<a href="' . route('accounts.show', [$account->id]) . '">View more</a>'
:
'<a href="' . route('accounts.index') . '">View more</a>';
@@ -371,7 +338,6 @@ class ChartController extends BaseController
];
foreach ($accounts as $account) {
\Log::debug('Now building series for ' . $account->name);
$data['series'][] = $this->_chart->account($account, $start, $end);
}
@@ -390,7 +356,7 @@ class ChartController extends BaseController
{
$account = $this->_accounts->findByName($name);
$date = Carbon::createFromDate($year, $month, $day);
$date = Carbon::createFromDate($year, $month, $day);
$result = $this->_chart->accountDailySummary($account, $date);
return View::make('charts.info')->with('rows', $result['rows'])->with('sum', $result['sum'])->with(
@@ -414,7 +380,7 @@ class ChartController extends BaseController
public function homeCategories()
{
$start = Session::get('start');
$end = Session::get('end');
$end = Session::get('end');
return Response::json($this->_chart->categories($start, $end));

View File

@@ -38,6 +38,10 @@ class HomeController extends BaseController
*/
public function index()
{
// Queue::push(function($job)
// {
// Log::debug('This is a job!');
// });
\Event::fire('limits.check');
\Event::fire('piggybanks.check');

View File

@@ -0,0 +1,46 @@
<?php
/**
* Class MigrateController
*/
class MigrateController extends BaseController
{
/**
* @return $this
*/
public function index()
{
return View::make('migrate.index')->with('index', 'Migration');
}
/**
*
*/
public function upload()
{
if (Input::hasFile('file') && Input::file('file')->isValid()) {
// move file to storage:
// ->move($destinationPath, $fileName);
$path = storage_path();
$fileName = 'firefly-iii-import-' . date('Y-m-d-H-i') . '.json';
$fullName = $path . DIRECTORY_SEPARATOR . $fileName;
if (is_writable($path)) {
Input::file('file')->move($path, $fileName);
// so now we push something in a queue and do something with it! Yay!
\Log::debug('Pushed a job to start the import.');
Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => \Auth::user()->id]);
Session::flash('success', 'The import job has been queued. Please be patient. Data will appear');
return Redirect::route('index');
}
Session::flash('error', 'Could not save file to storage.');
return Redirect::route('migrate.index');
} else {
Session::flash('error', 'Please upload a file.');
return Redirect::route('migrate.index');
}
}
}

View File

@@ -197,6 +197,7 @@ class TransactionController extends BaseController
}
// trigger the creation for recurring transactions.
Event::fire('journals.store',[$journal]);
if (Input::get('create') == '1') {
return Redirect::route('transactions.create', [$what])->withInput();
@@ -225,6 +226,7 @@ class TransactionController extends BaseController
if ($journal->validate()) {
// has been saved, return to index:
Session::flash('success', 'Transaction updated!');
Event::fire('journals.update',[$journal]);
return Redirect::route('transactions.index');
} else {

View File

@@ -25,8 +25,8 @@ class CreateRecurringTransactionsTable extends Migration
$table->integer('user_id')->unsigned();
$table->string('name', 50);
$table->string('match', 255);
$table->decimal('amount_max', 10, 2);
$table->decimal('amount_min', 10, 2);
$table->decimal('amount_max', 10, 2);
$table->date('date');
$table->boolean('active');

View File

@@ -24,6 +24,7 @@ class CreateTransactionJournalsTable extends Migration
$table->timestamps();
$table->integer('user_id')->unsigned();
$table->integer('transaction_type_id')->unsigned();
$table->integer('recurring_transaction_id')->unsigned()->nullable();
$table->integer('transaction_currency_id')->unsigned();
$table->string('description', 255)->nullable();
$table->boolean('completed');
@@ -34,6 +35,11 @@ class CreateTransactionJournalsTable extends Migration
->references('id')->on('transaction_types')
->onDelete('cascade');
// connect transaction journals to recurring transactions
$table->foreign('recurring_transaction_id')
->references('id')->on('recurring_transactions')
->onDelete('set null');
// connect transaction journals to transaction currencies
$table->foreign('transaction_currency_id')
->references('id')->on('transaction_currencies')

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImportmapsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('importmaps', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->integer('user_id')->unsigned();
$table->string('file',500);
// connect maps to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('importmaps');
}
}

View File

@@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImportentriesTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('importentries', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('class',200);
$table->integer('importmap_id')->unsigned();
$table->integer('old')->unsigned();
$table->integer('new')->unsigned();
// map import entries to import map.
// connect accounts to account_types
$table->foreign('importmap_id')
->references('id')->on('importmaps')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('importentries');
}
}

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateFailedJobsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('failed_jobs');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->increments('id');
$table->text('connection');
$table->text('queue');
$table->text('payload');
$table->timestamp('failed_at');
});
}
}

View File

@@ -11,16 +11,20 @@ class AccountTypeSeeder extends Seeder
DB::table('account_types')->delete();
AccountType::create(
['type' => 'Default account','editable' => true]
['type' => 'Default account', 'editable' => true]
);
AccountType::create(
['type' => 'Cash account','editable' => false]
['type' => 'Cash account', 'editable' => false]
);
AccountType::create(
['type' => 'Initial balance account','editable' => false]
['type' => 'Initial balance account', 'editable' => false]
);
AccountType::create(
['type' => 'Beneficiary account','editable' => true]
['type' => 'Beneficiary account', 'editable' => true]
);
AccountType::create(
['type' => 'Import account', 'editable' => false]
);
}

View File

@@ -2,8 +2,6 @@
namespace Firefly\Helper\Controllers;
use Firefly\Exception\FireflyException;
/**
* Class Account
*
@@ -11,15 +9,15 @@ use Firefly\Exception\FireflyException;
*/
class Account implements AccountInterface
{
/**
* @param \Account $account
*
* @return mixed
* @return \TransactionJournal|null
*/
public function openingBalanceTransaction(\Account $account)
{
return \TransactionJournal::
withRelevantData()->account($account)
return \TransactionJournal::withRelevantData()
->account($account)
->leftJoin('transaction_types', 'transaction_types.id', '=',
'transaction_journals.transaction_type_id')
->where('transaction_types.type', 'Opening balance')
@@ -27,55 +25,54 @@ class Account implements AccountInterface
}
/**
* @param \Account $account
* @param $perPage
* Since it is entirely possible the database is messed up somehow it might be that a transaction
* journal has only one transaction. This is mainly caused by wrong deletions and other artefacts from the past.
*
* @return mixed|void
* If it is the case, we remove $item and continue like nothing ever happened. This will however,
* mess up some statisics but we can live with that. We might be needing some cleanup routine in the future.
*
* For now, we simply warn the user of this.
*
* @param \Account $account
* @param $perPage
* @return array|mixed
* @throws \Firefly\Exception\FireflyException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function show(\Account $account, $perPage)
{
$start = \Session::get('start');
$end = \Session::get('end');
$stats = [
'budgets' => [],
'categories' => [],
'accounts' => []
'accounts' => []
];
$items = [];
// build a query:
$query = \TransactionJournal::withRelevantData()->defaultSorting()->account($account)->after($start)
$query = \TransactionJournal::withRelevantData()
->defaultSorting()
->account($account)
->after($start)
->before($end);
// filter some:
if (\Input::get('type')) {
switch (\Input::get('type')) {
case 'transactions':
$query->transactionTypes(['Deposit', 'Withdrawal']);
break;
case 'transfers':
$query->transactionTypes(['Transfer']);
break;
default:
throw new FireflyException('No case for type "' . \Input::get('type') . '"!');
break;
}
switch (\Input::get('type')) {
case 'transactions':
$query->transactionTypes(['Deposit', 'Withdrawal']);
break;
case 'transfers':
$query->transactionTypes(['Transfer']);
break;
}
if (\Input::get('show')) {
switch (\Input::get('show')) {
case 'expenses':
case 'out':
$query->lessThan(0);
break;
case 'income':
case 'in':
$query->moreThan(0);
break;
default:
throw new FireflyException('No case for show "' . \Input::get('show') . '"!');
break;
}
switch (\Input::get('show')) {
case 'expenses':
case 'out':
$query->lessThan(0);
break;
case 'income':
case 'in':
$query->moreThan(0);
break;
}
@@ -91,26 +88,11 @@ class Account implements AccountInterface
foreach ($result as $index => $item) {
foreach ($item->components as $component) {
if ($component->class == 'Budget') {
$stats['budgets'][$component->id] = $component;
}
if ($component->class == 'Category') {
$stats['categories'][$component->id] = $component;
}
$stats[$component->class][$component->id] = $component;
}
// since it is entirely possible the database is messed up somehow
// it might be that a transaction journal has only one transaction.
// this is mainly caused by wrong deletions and other artefacts from the past.
// if it is the case, we remove $item and continue like nothing ever happened.
// this will however, mess up some statisics but we can live with that.
// we might be needing some cleanup routine in the future.
// for now, we simply warn the user of this.
if (count($item->transactions) < 2) {
\Session::flash('warning',
'Some transactions are incomplete; they will not be shown. Statistics may differ.');
\Session::flash('warning', 'Some transactions are incomplete; they will not be shown.');
unset($result[$index]);
continue;
}
@@ -138,7 +120,6 @@ class Account implements AccountInterface
->transactionTypes(['Transfer'])->sum('transactions.amount'));
$trfDiff = $trfIn + $trfOut;
$stats['period'] = [
'in' => $trIn,
'out' => $trOut,
@@ -155,7 +136,5 @@ class Account implements AccountInterface
];
return $return;
}
}

View File

@@ -13,6 +13,11 @@ class Budget implements BudgetInterface
{
/**
* First, loop all budgets, all of their limits and all repetitions to get an overview per period
* and some basic information about that repetition's data.
*
*
*
* @param Collection $budgets
*
* @return mixed|void
@@ -21,32 +26,30 @@ class Budget implements BudgetInterface
{
$return = [];
/** @var \Budget $budget */
foreach ($budgets as $budget) {
/** @var \Limit $limit */
foreach ($budget->limits as $limit) {
/** @var \LimitRepetition $rep */
foreach ($limit->limitrepetitions as $rep) {
$periodOrder = $rep->periodOrder();
$period = $rep->periodShow();
$return[$periodOrder] = isset($return[$periodOrder])
? $return[$periodOrder]
: ['date' => $period,
'dateObject' => $rep->startdate,
'start' => $rep->startdate,
'end' => $rep->enddate,
'budget_id' => $limit->budget_id];
/** @var \LimitRepetition $repetition */
foreach ($limit->limitrepetitions as $repetition) {
$repetition->left = $repetition->left();
$periodOrder = $repetition->periodOrder();
$period = $repetition->periodShow();
if (!isset($return[$periodOrder])) {
}
}
}
// put all the budgets under their respective date:
foreach ($budgets as $budget) {
foreach ($budget->limits as $limit) {
foreach ($limit->limitrepetitions as $rep) {
$rep->left = $rep->left();
$return[$periodOrder] = [
'date' => $period,
'start' => $repetition->startdate,
'end' => $repetition->enddate,
'budget_id' => $budget->id,
'limitrepetitions' => [$repetition]
];
} else {
$return[$periodOrder]['limitrepetitions'][] = $repetition;
}
$month = $rep->periodOrder();
$return[$month]['limitrepetitions'][] = $rep;
}
}
}
@@ -56,30 +59,24 @@ class Budget implements BudgetInterface
}
/**
* Get a repetition (complex because of user check)
* and then get the transactions in it.
* @param $repetitionId
*
* @return array
*/
public function organizeRepetition($repetitionId)
public function organizeRepetition(\LimitRepetition $repetition)
{
$result = [];
$repetition = \LimitRepetition::with('limit', 'limit.budget')->leftJoin(
'limits', 'limit_repetitions.limit_id', '=', 'limits.id'
)->leftJoin('components', 'limits.component_id', '=', 'components.id')->where(
'components.user_id', \Auth::user()->id
)
->where('limit_repetitions.id', $repetitionId)->first(['limit_repetitions.*']);
// get transactions:
$set = $repetition->limit->budget->transactionjournals()->with(
'transactions', 'transactions.account', 'components', 'transactiontype'
)->leftJoin(
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
)->where('transaction_types.type', 'Withdrawal')->where(
'date', '>=', $repetition->startdate->format('Y-m-d')
)->where('date', '<=', $repetition->enddate->format('Y-m-d'))->orderBy('date', 'DESC')->orderBy(
'id', 'DESC'
)->get(['transaction_journals.*']);
$set = $repetition->limit->budget
->transactionjournals()
->withRelevantData()
->transactionTypes(['Withdrawal'])
->after($repetition->startdate)
->before($repetition->enddate)
->defaultSorting()
->get(['transaction_journals.*']);
$result[0] = [
'date' => $repetition->periodShow(),
@@ -93,8 +90,10 @@ class Budget implements BudgetInterface
}
/**
*
*
* @param \Budget $budget
* @param bool $useSessionDates
* @param bool $useSessionDates
*
* @return array|mixed
* @throws \Firefly\Exception\FireflyException
@@ -102,15 +101,15 @@ class Budget implements BudgetInterface
public function organizeRepetitions(\Budget $budget, $useSessionDates = false)
{
$sessionStart = \Session::get('start');
$sessionEnd = \Session::get('end');
$sessionEnd = \Session::get('end');
$result = [];
$result = [];
$inRepetition = [];
// get the limits:
if ($useSessionDates) {
$limits = $budget->limits()->where('startdate', '>=', $sessionStart->format('Y-m-d'))->where(
'startdate', '<=', $sessionEnd->format('Y-m-d')
'startdate', '<=', $sessionEnd->format('Y-m-d')
)->get();
} else {
$limits = $budget->limits;
@@ -119,7 +118,7 @@ class Budget implements BudgetInterface
/** @var \Limit $limit */
foreach ($limits as $limit) {
foreach ($limit->limitrepetitions as $repetition) {
$order = $repetition->periodOrder();
$order = $repetition->periodOrder();
$result[$order] = [
'date' => $repetition->periodShow(),
'limitrepetition' => $repetition,
@@ -127,16 +126,14 @@ class Budget implements BudgetInterface
'journals' => [],
'paginated' => false
];
$transactions = [];
$set = $budget->transactionjournals()->with(
'transactions', 'transactions.account', 'components', 'transactiontype'
)->leftJoin(
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
)->where('transaction_types.type', 'Withdrawal')->where(
'date', '>=', $repetition->startdate->format('Y-m-d')
)->where('date', '<=', $repetition->enddate->format('Y-m-d'))->orderBy('date', 'DESC')->orderBy(
'id', 'DESC'
)->get(['transaction_journals.*']);
$transactions = [];
$set = $budget->transactionjournals()
->withRelevantData()
->transactionTypes(['Withdrawal'])
->after($repetition->startdate)
->before($repetition->enddate)
->defaultSorting()
->get(['transaction_journals.*']);
foreach ($set as $entry) {
$transactions[] = $entry;
$inRepetition[] = $entry->id;
@@ -146,30 +143,17 @@ class Budget implements BudgetInterface
}
if ($useSessionDates === false) {
$query = $budget->transactionjournals()->withRelevantData()->defaultSorting();
if (count($inRepetition) > 0) {
$query = $budget->transactionjournals()->with(
'transactions', 'transactions.account', 'components', 'transactiontype',
'transactions.account.accounttype'
)->whereNotIn(
'transaction_journals.id', $inRepetition
)->orderBy('date', 'DESC')->orderBy(
'transaction_journals.id', 'DESC'
);
} else {
$query = $budget->transactionjournals()->with(
'transactions', 'transactions.account', 'components', 'transactiontype',
'transactions.account.accounttype'
)->orderBy('date', 'DESC')->orderBy(
'transaction_journals.id', 'DESC'
);
$query->whereNotIn('transaction_journals.id', $inRepetition);
}
// build paginator:
$perPage = 25;
$perPage = 25;
$totalItems = $query->count();
$page = intval(\Input::get('page')) > 1 ? intval(\Input::get('page')) : 1;
$skip = ($page - 1) * $perPage;
$set = $query->skip($skip)->take($perPage)->get();
$page = intval(\Input::get('page')) > 1 ? intval(\Input::get('page')) : 1;
$skip = ($page - 1) * $perPage;
$set = $query->skip($skip)->take($perPage)->get();
// stupid paginator!
$items = [];
@@ -177,9 +161,12 @@ class Budget implements BudgetInterface
foreach ($set as $item) {
$items[] = $item;
}
$paginator = \Paginator::make($items, $totalItems, $perPage);
$result['0000'] = ['date' => 'Not in an envelope', 'limit' => null, 'paginated' => true,
'journals' => $paginator];
$paginator = \Paginator::make($items, $totalItems, $perPage);
$result['0000'] = [
'date' => 'Not in an envelope',
'limit' => null,
'paginated' => true,
'journals' => $paginator];
}
krsort($result);
@@ -196,13 +183,12 @@ class Budget implements BudgetInterface
$inRepetitions = [];
foreach ($budget->limits as $limit) {
foreach ($limit->limitrepetitions as $repetition) {
$set = $budget->transactionjournals()->leftJoin(
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
)->where('transaction_types.type', 'Withdrawal')->where(
'date', '>=', $repetition->startdate->format('Y-m-d')
)->where('date', '<=', $repetition->enddate->format('Y-m-d'))->orderBy('date', 'DESC')->get(
['transaction_journals.id']
);
$set = $budget->transactionjournals()
->transactionTypes(['Withdrawal'])
->after($repetition->startdate)
->before($repetition->enddate)
->defaultSorting()
->get(['transaction_journals.id']);
foreach ($set as $item) {
$inRepetitions[] = $item->id;
}
@@ -210,21 +196,17 @@ class Budget implements BudgetInterface
}
$query = $budget->transactionjournals()->with(
'transactions', 'transactions.account', 'components', 'transactiontype',
'transactions.account.accounttype'
)->whereNotIn(
'transaction_journals.id', $inRepetitions
)->orderBy('date', 'DESC')->orderBy(
'transaction_journals.id', 'DESC'
);
$query = $budget->transactionjournals()
->withRelevantData()
->whereNotIn('transaction_journals.id', $inRepetitions)
->defaultSorting();
// build paginator:
$perPage = 25;
$perPage = 25;
$totalItems = $query->count();
$page = intval(\Input::get('page')) > 1 ? intval(\Input::get('page')) : 1;
$skip = ($page - 1) * $perPage;
$set = $query->skip($skip)->take($perPage)->get();
$page = intval(\Input::get('page')) > 1 ? intval(\Input::get('page')) : 1;
$skip = ($page - 1) * $perPage;
$set = $query->skip($skip)->take($perPage)->get();
// stupid paginator!
$items = [];
@@ -233,8 +215,12 @@ class Budget implements BudgetInterface
$items[] = $item;
}
$paginator = \Paginator::make($items, $totalItems, $perPage);
$result = [0 => ['date' => 'Not in an envelope', 'limit' => null, 'paginated' => true,
'journals' => $paginator]];
$result = [0 => [
'date' => 'Not in an envelope',
'limit' => null,
'paginated' => true,
'journals' => $paginator
]];
return $result;
}

View File

@@ -23,7 +23,7 @@ interface BudgetInterface
*
* @return mixed
*/
public function organizeRepetition($repetitionId);
public function organizeRepetition(\LimitRepetition $repetition);
/**

View File

@@ -4,6 +4,7 @@ namespace Firefly\Helper\Controllers;
use Carbon\Carbon;
use Firefly\Exception\FireflyException;
use Illuminate\Support\Collection;
/**
* Class Chart
@@ -23,8 +24,8 @@ class Chart implements ChartInterface
public function account(\Account $account, Carbon $start, Carbon $end)
{
$current = clone $start;
$today = new Carbon;
$return = ['name' => $account->name, 'id' => $account->id, 'data' => []];
$today = new Carbon;
$return = ['name' => $account->name, 'id' => $account->id, 'data' => []];
while ($current <= $end) {
if ($current > $today) {
@@ -106,7 +107,7 @@ class Chart implements ChartInterface
$data = [];
$budgets = \Auth::user()->budgets()->with(
$budgets = \Auth::user()->budgets()->with(
['limits' => function ($q) {
$q->orderBy('limits.startdate', 'ASC');
}, 'limits.limitrepetitions' => function ($q) use ($start) {
@@ -117,6 +118,7 @@ class Chart implements ChartInterface
$limitInPeriod = '';
$spentInPeriod = '';
/** @var \Budget $budget */
foreach ($budgets as $budget) {
$budget->count = 0;
foreach ($budget->limits as $limit) {
@@ -129,21 +131,38 @@ class Chart implements ChartInterface
$rep->left = $rep->left();
// overspent:
if ($rep->left < 0) {
$rep->spent = ($rep->left * -1) + $rep->amount;
$rep->overspent = $rep->left * -1;
$total = $rep->spent + $rep->overspent;
$rep->spent_pct = round(($rep->spent / $total) * 100);
$rep->spent = ($rep->left * -1) + $rep->amount;
$rep->overspent = $rep->left * -1;
$total = $rep->spent + $rep->overspent;
$rep->spent_pct = round(($rep->spent / $total) * 100);
$rep->overspent_pct = 100 - $rep->spent_pct;
} else {
$rep->spent = $rep->amount - $rep->left;
$rep->spent = $rep->amount - $rep->left;
$rep->spent_pct = round(($rep->spent / $rep->amount) * 100);
$rep->left_pct = 100 - $rep->spent_pct;
$rep->left_pct = 100 - $rep->spent_pct;
}
}
$budget->count += count($limit->limitrepetitions);
}
if ($budget->count == 0) {
// get expenses in period until today, starting at $start.
$end = \Session::get('end');
$expenses = $budget->transactionjournals()->after($start)->before($end)
->transactionTypes(
['Withdrawal']
)->get();
$budget->spentInPeriod = 0;
/** @var \TransactionJournal $expense */
foreach ($expenses as $expense) {
$transaction = $expense->transactions[1];
if (!is_null($transaction)) {
$budget->spentInPeriod += floatval($transaction->amount);
}
}
}
}
@@ -161,16 +180,25 @@ class Chart implements ChartInterface
foreach ($budgets as $budget) {
if ($budget->count > 0) {
$data['labels'][] = wordwrap($budget->name, 12, "<br>");
}
foreach ($budget->limits as $limit) {
foreach ($limit->limitrepetitions as $rep) {
//0: envelope for period:
$amount = floatval($rep->amount);
$spent = $rep->spent;
$color = $spent > $amount ? '#FF0000' : null;
$data['series'][0]['data'][] = ['y' => $amount, 'id' => 'amount-' . $rep->id];
$data['series'][1]['data'][] = ['y' => $rep->spent, 'color' => $color, 'id' => 'spent-' . $rep->id];
$data['labels'][] = $budget->name;
foreach ($budget->limits as $limit) {
foreach ($limit->limitrepetitions as $rep) {
//0: envelope for period:
$amount = floatval($rep->amount);
$spent = $rep->spent;
$color = $spent > $amount ? '#FF0000' : null;
$data['series'][0]['data'][] = ['y' => $amount, 'id' => 'amount-' . $rep->id];
$data['series'][1]['data'][] = ['y' => $rep->spent, 'color' => $color,
'id' => 'spent-' . $rep->id];
}
}
} else {
// add for "empty" budget:
if ($budget->spentInPeriod > 0) {
$data['labels'][] = $budget->name;
$data['series'][0]['data'][] = ['y' => null, 'id' => 'amount-norep-' . $budget->id];
$data['series'][1]['data'][] = ['y' => $budget->spentInPeriod,
'id' => 'spent-norep-' . $budget->id];
}
}
@@ -211,10 +239,10 @@ class Chart implements ChartInterface
. ' transactions!');
}
$transaction = $journal->transactions[0];
$amount = floatval($transaction->amount);
$amount = floatval($transaction->amount);
// get budget from journal:
$category = $journal->categories()->first();
$category = $journal->categories()->first();
$categoryName = is_null($category) ? '(no category)' : $category->name;
$result[$categoryName] = isset($result[$categoryName]) ? $result[$categoryName] + floatval($amount)
@@ -335,7 +363,7 @@ class Chart implements ChartInterface
// get sum for current range:
$journals = \TransactionJournal::
$journals = \TransactionJournal::
with(
['transactions' => function ($q) {
$q->where('amount', '>', 0);
@@ -360,7 +388,7 @@ class Chart implements ChartInterface
. ' transactions!');
}
$transaction = $journal->transactions[0];
$amount = floatval($transaction->amount);
$amount = floatval($transaction->amount);
$currentSum += $amount;
}
@@ -401,4 +429,150 @@ class Chart implements ChartInterface
}
/**
* @param \Budget $budget
* @param Carbon $date
*
* @return float|null
*/
public function spentOnDay(\Budget $budget, Carbon $date)
{
return floatval(
\Transaction::
leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
'transaction_journals.id'
)->where('component_transaction_journal.component_id', '=', $budget->id)->where(
'transaction_journals.date', $date->format('Y-m-d')
)->where('amount', '>', 0)->sum('amount')
);
}
/**
* @param \Budget $budget
*
* @return int[]
*/
public function allJournalsInBudgetEnvelope(\Budget $budget)
{
$inRepetitions = [];
foreach ($budget->limits as $limit) {
foreach ($limit->limitrepetitions as $repetition) {
$set = $budget
->transactionjournals()
->transactionTypes(['Withdrawal'])
->after($repetition->startdate)
->before($repetition->enddate)
->get(['transaction_journals.id']);
foreach ($set as $item) {
$inRepetitions[] = $item->id;
}
}
}
return $inRepetitions;
}
/**
* @param \Budget $budget
* @param array $ids
*
* @return mixed|void
*/
public function journalsNotInSet(\Budget $budget, array $ids)
{
$query = $budget->transactionjournals()
->whereNotIn('transaction_journals.id', $ids)
->orderBy('date', 'DESC')
->orderBy('transaction_journals.id', 'DESC');
$result = $query->get(['transaction_journals.id']);
$set = [];
foreach ($result as $entry) {
$set[] = $entry->id;
}
return $set;
}
/**
* @param array $set
*
* @return mixed
*/
public function transactionsByJournals(array $set)
{
$transactions = \Transaction::whereIn('transaction_journal_id', $set)
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->groupBy('transaction_journals.date')
->where('amount', '>', 0)->get(['transaction_journals.date', \DB::Raw('SUM(`amount`) as `aggregate`')]);
return $transactions;
}
/**
* Get all limit (LimitRepetitions) for a budget falling in a certain date range.
*
* @param \Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function limitsInRange(\Budget $budget, Carbon $start, Carbon $end)
{
$reps = new Collection;
/** @var \Limit $limit */
foreach ($budget->limits as $limit) {
$set = $limit->limitrepetitions()->where(
function ($q) use ($start, $end) {
// startdate is between range
$q->where(
function ($q) use ($start, $end) {
$q->where('startdate', '>=', $start->format('Y-m-d'));
$q->where('startdate', '<=', $end->format('Y-m-d'));
}
);
// or enddate is between range.
$q->orWhere(
function ($q) use ($start, $end) {
$q->where('enddate', '>=', $start->format('Y-m-d'));
$q->where('enddate', '<=', $end->format('Y-m-d'));
}
);
}
)->get();
$reps = $reps->merge($set);
}
return $reps;
}
/**
* We check how much money has been spend on the limitrepetition (aka: the current envelope) in the period denoted.
* Aka, we have a certain amount of money in an envelope and we wish to know how much we've spent between the dates
* entered. This can be a partial match with the date range of the envelope or no match at all.
*
* @param \LimitRepetition $repetition
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function spentOnLimitRepetitionBetweenDates(\LimitRepetition $repetition, Carbon $start, Carbon $end) {
return floatval(
\Transaction::
leftJoin('transaction_journals', 'transaction_journals.id', '=','transactions.transaction_journal_id')
->leftJoin('component_transaction_journal', 'component_transaction_journal.transaction_journal_id','=',
'transaction_journals.id'
)->where('component_transaction_journal.component_id', '=', $repetition->limit->budget->id)->where(
'transaction_journals.date', '>=', $start->format('Y-m-d')
)->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->where(
'amount', '>', 0
)->sum('amount')) ;
}
}

View File

@@ -54,4 +54,61 @@ interface ChartInterface
* @return mixed
*/
public function categoryShowChart(\Category $category, $range, Carbon $start, Carbon $end);
/**
* @param \Budget $budget
* @param Carbon $date
*
* @return float|null
*/
public function spentOnDay(\Budget $budget, Carbon $date);
/**
* @param \Budget $budget
*
* @return int[]
*/
public function allJournalsInBudgetEnvelope(\Budget $budget);
/**
* @param \Budget $budget
* @param array $ids
*
* @return mixed
*/
public function journalsNotInSet(\Budget $budget, array $ids);
/**
* @param array $set
*
* @return mixed
*/
public function transactionsByJournals(array $set);
/**
* Get all limit (LimitRepetitions) for a budget falling in a certain date range.
*
* @param \Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function limitsInRange(\Budget $budget, Carbon $start, Carbon $end);
/**
* We check how much money has been spend on the limitrepetition (aka: the current envelope) in the period denoted.
* Aka, we have a certain amount of money in an envelope and we wish to know how much we've spent between the dates
* entered. This can be a partial match with the date range of the envelope or no match at all.
*
* @param \LimitRepetition $repetition
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function spentOnLimitRepetitionBetweenDates(\LimitRepetition $repetition, Carbon $start, Carbon $end);
}

View File

@@ -1,47 +0,0 @@
<?php
namespace Firefly\Helper\Form;
/**
* Class FormHelper
*
* @package Firefly\Form
*/
class FormHelper
{
/**
* @param null $value
*
* @return string
*/
public function budget($value = null)
{
$str = '<select name="budget_id" class="form-control">';
$str .= '<option value="0" label="(no budget)"';
if (is_null($value) || intval($value) == 0) {
$str .= ' selected="selected"';
}
$str .= '</option>';
/** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgets */
$budgets = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
$list = $budgets->getAsSelectList();
foreach ($list as $id => $name) {
$str .= '<option value="' . e($id) . '" label="' . e($name) . '"';
if ($id == intval($value)) {
$str .= ' selected="selected"';
}
$str .= '>' . e($name) . '</option>';
}
$str .= '</select>';
return $str;
}
}

View File

@@ -1,35 +0,0 @@
<?php
namespace Firefly\Helper\Form;
use Illuminate\Events\Dispatcher;
/**
* Class FormTrigger
*
* @package Firefly\Helper\Form
*/
class FormTrigger
{
public function registerFormExtensions()
{
\Form::macro(
'budget', function () {
$helper = new FormHelper;
return $helper->budget();
}
);
}
/**
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{
$events->listen('laravel.booted', 'Firefly\Helper\Form\FormTrigger@registerFormExtensions');
}
}

View File

@@ -1,327 +0,0 @@
<?php
namespace Firefly\Helper\Migration;
use Carbon\Carbon;
use Firefly\Exception\FireflyException;
/**
* Class MigrationHelper
*
* @package Firefly\Helper\Migration
*/
class MigrationHelper implements MigrationHelperInterface
{
protected $path;
protected $JSON;
protected $map = [];
/**
* @param $path
*
* @return mixed|void
*/
public function loadFile($path)
{
$this->path = $path;
}
/**
* @return bool
*/
public function validFile()
{
// file does not exist:
if (!file_exists($this->path)) {
\Log::error('Migration file ' . $this->path . ' does not exist!');
return false;
}
// load the content:
$content = file_get_contents($this->path);
if ($content === false) {
return false;
}
// parse the content
$this->JSON = json_decode($content);
if (is_null($this->JSON)) {
return false;
}
\Log::info('Migration file ' . $this->path . ' is valid!');
return true;
}
/**
* @return bool
*/
public function migrate()
{
\Log::info('Start of migration.');
\DB::beginTransaction();
try {
// create cash account:
$this->_createCashAccount();
$this->_importAccounts();
$this->_importComponents();
//$this->_importPiggybanks();
// create transactions:
$this->_importTransactions();
// create transfers:
$this->_importTransfers();
// create limits:
$this->_importLimits();
} catch (FireflyException $e) {
\DB::rollBack();
\Log::error('Rollback because of error!');
\Log::error($e->getMessage());
return false;
}
\DB::commit();
\Log::info('Done!');
return true;
}
/**
*
*/
protected function _createCashAccount()
{
$cashAT = \AccountType::where('description', 'Cash account')->first();
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$cash = $accounts->store(['name' => 'Cash account', 'account_type' => $cashAT, 'active' => 0]);
\Log::info('Created cash account (#' . $cash->id . ')');
$this->map['cash'] = $cash;
}
/**
*
*/
protected function _importAccounts()
{
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
\Log::info('Going to import ' . count($this->JSON->accounts) . ' accounts.');
foreach ($this->JSON->accounts as $entry) {
// create account:
if ($entry->openingbalance == 0) {
$account = $accounts->store(['name' => $entry->name]);
} else {
$account = $accounts->storeWithInitialBalance(
['name' => $entry->name],
new Carbon($entry->openingbalancedate),
floatval($entry->openingbalance)
);
}
$this->map['accounts'][$entry->id] = $account;
\Log::info('Imported account "' . $entry->name . '" with balance ' . $entry->openingbalance);
}
}
/**
*
*/
protected function _importComponents()
{
$beneficiaryAT = \AccountType::where('description', 'Beneficiary account')->first();
foreach ($this->JSON->components as $entry) {
switch ($entry->type->type) {
case 'beneficiary':
/** @noinspection PhpParamsInspection */
$beneficiary = $this->_importBeneficiary($entry, $beneficiaryAT);
$this->map['accounts'][$entry->id] = $beneficiary;
break;
case 'category':
$component = $this->_importCategory($entry);
$this->map['categories'][$entry->id] = $component;
break;
case 'budget':
$component = $this->_importBudget($entry);
$this->map['budgets'][$entry->id] = $component;
break;
}
}
}
/**
* @param $component
* @param \AccountType $beneficiaryAT
*
* @return mixed
*/
protected function _importBeneficiary($component, \AccountType $beneficiaryAT)
{
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
return $accounts->store(
[
'name' => $component->name,
'account_type' => $beneficiaryAT
]
);
}
/**
* @param $component
*
* @return mixed
*/
protected function _importCategory($component)
{
/** @var \Firefly\Storage\Component\ComponentRepositoryInterface $components */
$components = \App::make('Firefly\Storage\Component\ComponentRepositoryInterface');
return $components->store(['name' => $component->name, 'class' => 'Category']);
}
/**
* @param $component
*
* @return mixed
*/
protected function _importBudget($component)
{
/** @var \Firefly\Storage\Component\ComponentRepositoryInterface $components */
$components = \App::make('Firefly\Storage\Component\ComponentRepositoryInterface');
return $components->store(['name' => $component->name, 'class' => 'Budget']);
}
/**
*
*/
protected function _importTransactions()
{
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */
$journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
// loop component_transaction to find beneficiaries, categories and budgets:
$beneficiaries = [];
$categories = [];
$budgets = [];
foreach ($this->JSON->component_transaction as $entry) {
// beneficiaries
if (isset($this->map['accounts'][$entry->component_id])) {
$beneficiaries[$entry->transaction_id] = $this->map['accounts'][$entry->component_id];
}
// categories
if (isset($this->map['categories'][$entry->component_id])) {
$categories[$entry->transaction_id] = $this->map['categories'][$entry->component_id];
}
// budgets:
if (isset($this->map['budgets'][$entry->component_id])) {
$budgets[$entry->transaction_id] = $this->map['budgets'][$entry->component_id];
}
}
foreach ($this->JSON->transactions as $entry) {
// to properly save the amount, do it times -1:
$amount = $entry->amount * -1;
/** @var \Account $fromAccount */
$fromAccount = isset($this->map['accounts'][$entry->account_id])
? $this->map['accounts'][$entry->account_id] : false;
/** @var \Account $toAccount */
$toAccount = isset($beneficiaries[$entry->id]) ? $beneficiaries[$entry->id] : $this->map['cash'];
$date = new Carbon($entry->date);
$journal = $journals->createSimpleJournal($fromAccount, $toAccount, $entry->description, $amount, $date);
// save budgets and categories, on the journal
if (isset($budgets[$entry->id])) {
$budget = $budgets[$entry->id];
$journal->budgets()->save($budget);
}
if (isset($categories[$entry->id])) {
$category = $categories[$entry->id];
$journal->categories()->save($category);
}
}
}
/**
*
*/
protected function _importTransfers()
{
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */
$journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
foreach ($this->JSON->transfers as $entry) {
// to properly save the amount, do it times 1 (?):
$amount = $entry->amount * -1;
/** @var \Account $fromAccount */
$fromAccount = isset($this->map['accounts'][$entry->accountfrom_id])
? $this->map['accounts'][$entry->accountto_id] : false;
/** @var \Account $toAccount */
$toAccount = isset($this->map['accounts'][$entry->accountto_id])
? $this->map['accounts'][$entry->accountfrom_id] : false;
$date = new Carbon($entry->date);
$journals->createSimpleJournal($fromAccount, $toAccount, $entry->description, $amount, $date);
}
}
/**
*
*/
protected function _importLimits()
{
\Log::info('Importing limits');
foreach ($this->JSON->limits as $entry) {
\Log::debug(
'Now at #' . $entry->id . ': EUR ' . $entry->amount . ' for month ' . $entry->date
. ' and componentID: ' . $entry->component_id
);
$budget = isset($this->map['budgets'][$entry->component_id]) ? $this->map['budgets'][$entry->component_id]
: null;
if (!is_null($budget)) {
\Log::debug('Found budget for this limit: #' . $budget->id . ', ' . $budget->name);
$limit = new \Limit;
$limit->budget()->associate($budget);
$limit->startdate = new Carbon($entry->date);
$limit->amount = floatval($entry->amount);
$limit->repeats = 0;
$limit->repeat_freq = 'monthly';
try {
$limit->save();
} catch (\Exception $e) {
}
} else {
\Log::warning('No budget for this limit!');
}
// create repeat thing should not be necessary.
}
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace Firefly\Helper\Migration;
/**
* Interface MigrationHelperInterface
*
* @package Firefly\Helper\Migration
*/
interface MigrationHelperInterface
{
/**
* @param $path
*
* @return mixed
*/
public function loadFile($path);
/**
* @return mixed
*/
public function validFile();
/**
* @return mixed
*/
public function migrate();
}

View File

@@ -0,0 +1,674 @@
<?php
namespace Firefly\Queue;
use Carbon\Carbon;
use Illuminate\Queue\Jobs\Job;
/**
* Class Import
*
* @package Firefly\Queue
*/
class Import
{
/** @var \Firefly\Storage\Account\AccountRepositoryInterface */
protected $_accounts;
/** @var \Firefly\Storage\Import\ImportRepositoryInterface */
protected $_repository;
/** @var \Firefly\Storage\Budget\BudgetRepositoryInterface */
protected $_budgets;
/** @var \Firefly\Storage\Category\CategoryRepositoryInterface */
protected $_categories;
/** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface */
protected $_journals;
/** @var \Firefly\Storage\Limit\LimitRepositoryInterface */
protected $_limits;
/** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface */
protected $_piggybanks;
/** @var \Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface */
protected $_recurring;
/**
*
*/
public function __construct()
{
$this->_accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface');
$this->_budgets = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
$this->_categories = \App::make('Firefly\Storage\Category\CategoryRepositoryInterface');
$this->_journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
$this->_limits = \App::make('Firefly\Storage\Limit\LimitRepositoryInterface');
$this->_piggybanks = \App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
$this->_recurring = \App::make('Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface');
}
/**
* @param Job $job
* @param array $payload
*/
public function cleanImportAccount(Job $job, array $payload)
{
$importAccountType = $this->_accounts->findAccountType('Import account');
$importAccounts = $this->_accounts->getByAccountType($importAccountType);
if (count($importAccounts) == 0) {
$job->delete();
} else if (count($importAccounts) == 1) {
/** @var \Account $importAccount */
$importAccount = $importAccounts[0];
$transactions = $importAccount->transactions()->get();
/** @var \Transaction $transaction */
foreach ($transactions as $transaction) {
$transaction->account()->associate($importAccount);
$transaction->save();
}
\Log::debug('Updated ' . count($transactions) . ' transactions from Import Account to cash.');
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*
* @throws \Firefly\Exception\FireflyException
*/
public function importComponent(Job $job, array $payload)
{
\Log::debug('Going to import component "' . $payload['data']['name'] . '".');
switch ($payload['data']['type']['type']) {
case 'beneficiary':
$payload['class'] = 'Account';
$payload['data']['account_type'] = 'Beneficiary account';
$this->importAccount($job, $payload);
break;
case 'budget':
$this->importBudget($job, $payload);
break;
case 'category':
$this->importCategory($job, $payload);
break;
case 'payer':
$job->delete();
break;
default:
$job->delete();
break;
}
}
/**
* Import a personal account or beneficiary as a new account.
*
* @param Job $job
* @param array $payload
*/
public function importAccount(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// maybe we've already imported this account:
$importEntry = $this->_repository->findImportEntry($importMap, 'Account', intval($payload['data']['id']));
// if so, delete job and return:
if (!is_null($importEntry)) {
$job->delete();
return;
}
// if we try to import a beneficiary, Firefly will "merge" already,
// so we don't care:
if (isset($payload['data']['account_type']) && $payload['data']['account_type'] == 'Beneficiary account') {
// store beneficiary
$acct = $this->_accounts->createOrFindBeneficiary($payload['data']['name']);
\Log::debug('Imported ' . $payload['class'] . ' "' . $payload['data']['name'] . '".');
$this->_repository->store($importMap, 'Account', $payload['data']['id'], $acct->id);
$job->delete();
return;
}
// but we cannot merge accounts, so we need to search first:
$acct = $this->_accounts->findByName($payload['data']['name']);
if (is_null($acct)) {
// store new one!
$acct = $this->_accounts->store((array)$payload['data']);
\Log::debug('Imported ' . $payload['class'] . ' "' . $payload['data']['name'] . '".');
$this->_repository->store($importMap, 'Account', $payload['data']['id'], $acct->id);
} else {
// use previous one!
\Log::debug('Already imported ' . $payload['class'] . ' "' . $payload['data']['name'] . '".');
$this->_repository->store($importMap, 'Account', $payload['data']['id'], $acct->id);
}
// and delete the job
$job->delete();
}
/**
* @param \User $user
*/
protected function overruleUser(\User $user)
{
$this->_accounts->overruleUser($user);
$this->_budgets->overruleUser($user);
$this->_categories->overruleUser($user);
$this->_journals->overruleUser($user);
$this->_limits->overruleUser($user);
$this->_repository->overruleUser($user);
$this->_piggybanks->overruleUser($user);
$this->_recurring->overruleUser($user);
}
/**
* Import a budget into Firefly.
*
* @param Job $job
* @param array $payload
*/
public function importBudget(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// maybe we've already imported this budget:
$bdg = $this->_budgets->findByName($payload['data']['name']);
if (is_null($bdg)) {
// we have not!
$bdg = $this->_budgets->store((array)$payload['data']);
$this->_repository->store($importMap, 'Budget', $payload['data']['id'], $bdg->id);
\Log::debug('Imported budget "' . $payload['data']['name'] . '".');
} else {
// we have!
$this->_repository->store($importMap, 'Budget', $payload['data']['id'], $bdg->id);
\Log::debug('Already had budget "' . $payload['data']['name'] . '".');
}
// delete job.
$job->delete();
}
/**
* Import a category into Firefly.
*
* @param Job $job
* @param array $payload
*/
public function importCategory(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// try to find budget:
$current = $this->_categories->findByName($payload['data']['name']);
if (is_null($current)) {
$cat = $this->_categories->store((array)$payload['data']);
$this->_repository->store($importMap, 'Category', $payload['data']['id'], $cat->id);
\Log::debug('Imported category "' . $payload['data']['name'] . '".');
} else {
$this->_repository->store($importMap, 'Category', $payload['data']['id'], $current->id);
\Log::debug('Already had category "' . $payload['data']['name'] . '".');
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importComponentTransaction(Job $job, array $payload)
{
if ($job->attempts() > 1) {
\Log::info('importComponentTransaction Job running for ' . $job->attempts() . 'th time!');
}
if ($job->attempts() > 30) {
\Log::error('importComponentTransaction Job running for ' . $job->attempts() . 'th time, so KILL!');
$job->delete();
return;
}
$oldComponentId = intval($payload['data']['component_id']);
$oldTransactionId = intval($payload['data']['transaction_id']);
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
$oldTransactionMap = $this->_repository->findImportEntry($importMap, 'Transaction', $oldTransactionId);
// we don't know what the component is, so we need to search for it in a set
// of possible types (Account / Beneficiary, Budget, Category)
/** @var \Importentry $oldComponentMap */
$oldComponentMap = $this->_repository->findImportComponentMap($importMap, $oldComponentId);
if (is_null($oldComponentMap)) {
\Log::debug('importComponentTransaction Could not run this one, waiting for five minutes...');
$job->release(300);
return;
}
$journal = $this->_journals->find($oldTransactionMap->new);
\Log::debug('Going to update ' . $journal->description);
// find the cash account:
switch ($oldComponentMap->class) {
case 'Budget':
// budget thing link:
$budget = $this->_budgets->find($oldComponentMap->new);
\Log::debug('Updating transactions budget.');
$journal->budgets()->save($budget);
$journal->save();
\Log::debug('Updated transactions budget.');
break;
case 'Category':
$category = $this->_categories->find($oldComponentMap->new);
$journal = $this->_journals->find($oldTransactionMap->new);
\Log::info('Updating transactions category (old id is #' . $oldComponentMap->old . ').');
if (!is_null($category)) {
$journal->categories()->save($category);
$journal->save();
\Log::info('Updated transactions category.');
} else {
\Log::error('No category mapping to old id #' . $oldComponentMap->old . ' found. Release for 5m!');
$job->release(300);
return;
}
break;
case 'Account':
\Log::info('Updating transactions Account.');
$account = $this->_accounts->find($oldComponentMap->new);
$journal = $this->_journals->find($oldTransactionMap->new);
if (is_null($account)) {
\Log::debug('Cash account is needed.');
$account = $this->_accounts->getCashAccount();
\Log::info($account);
}
foreach ($journal->transactions as $transaction) {
if ($transaction->account()->first()->account_type_id == 5) {
$transaction->account()->associate($account);
$transaction->save();
\Log::debug(
'Updated transactions (#' . $journal->id . '), #' . $transaction->id . '\'s Account.'
);
}
}
break;
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importLimit(Job $job, array $payload)
{
if ($job->attempts() > 30) {
\Log::error('importLimit Job running for ' . $job->attempts() . 'th time, so KILL!');
$job->delete();
return;
}
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// find the budget this limit is part of:
$importEntry = $this->_repository->findImportEntry(
$importMap, 'Budget',
intval($payload['data']['component_id'])
);
// budget is not yet imported:
if (is_null($importEntry)) {
\Log::debug(
'importLimit Cannot import limit #' . $payload['data']['id'] .
' because the budget is not here yet. #' . $job->attempts()
);
$job->release(300);
return;
}
// find similar limit:
\Log::debug('Trying to find budget with ID #' . $importEntry->new . ', based on entry #' . $importEntry->id);
$budget = $this->_budgets->find($importEntry->new);
if (!is_null($budget)) {
$current = $this->_limits->findByBudgetAndDate($budget, new Carbon($payload['data']['date']));
if (is_null($current)) {
// create it!
$payload['data']['budget_id'] = $budget->id;
$payload['data']['startdate'] = $payload['data']['date'];
$payload['data']['period'] = 'monthly';
$lim = $this->_limits->store((array)$payload['data']);
$this->_repository->store($importMap, 'Limit', $payload['data']['id'], $lim->id);
\Event::fire('limits.store', [$lim]);
\Log::debug('Imported ' . $payload['class'] . ', for ' . $budget->name . ' (' . $lim->startdate . ').');
} else {
// already has!
$this->_repository->store($importMap, 'Budget', $payload['data']['id'], $current->id);
\Log::debug(
'Already had ' . $payload['class'] . ', for ' . $budget->name . ' (' . $current->startdate . ').'
);
}
} else {
// cannot import component limit, no longer supported.
\Log::error('Cannot import limit for other than budget!');
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importPiggybank(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// try to find related piggybank:
$current = $this->_piggybanks->findByName($payload['data']['name']);
// we need an account to go with this piggy bank:
$set = $this->_accounts->getActiveDefault();
if (count($set) > 0) {
$account = $set[0];
$payload['data']['account_id'] = $account->id;
} else {
\Log::debug('Released job for work in five minutes...');
$job->release(300);
return;
}
if (is_null($current)) {
$payload['data']['targetamount'] = floatval($payload['data']['target']);
$payload['data']['repeats'] = 0;
$payload['data']['rep_every'] = 1;
$payload['data']['reminder_skip'] = 1;
$payload['data']['rep_times'] = 1;
$piggy = $this->_piggybanks->store((array)$payload['data']);
$this->_repository->store($importMap, 'Piggybank', $payload['data']['id'], $piggy->id);
\Log::debug('Imported ' . $payload['class'] . ' "' . $payload['data']['name'] . '".');
\Event::fire('piggybanks.store', [$piggy]);
} else {
$this->_repository->store($importMap, 'Piggybank', $payload['data']['id'], $current->id);
\Log::debug('Already had ' . $payload['class'] . ' "' . $payload['data']['name'] . '".');
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importPredictable(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// try to find related recurring transaction:
$current = $this->_recurring->findByName($payload['data']['description']);
if (is_null($current)) {
$payload['data']['name'] = $payload['data']['description'];
$payload['data']['match'] = join(',', explode(' ', $payload['data']['description']));
$pct = intval($payload['data']['pct']);
$payload['data']['amount_min'] = floatval($payload['data']['amount']) * ($pct / 100) * -1;
$payload['data']['amount_max'] = floatval($payload['data']['amount']) * (1 + ($pct / 100)) * -1;
$payload['data']['date'] = date('Y-m-') . $payload['data']['dom'];
$payload['data']['repeat_freq'] = 'monthly';
$payload['data']['active'] = intval($payload['data']['inactive']) == 1 ? 0 : 1;
$payload['data']['automatch'] = 1;
$recur = $this->_recurring->store((array)$payload['data']);
$this->_repository->store($importMap, 'RecurringTransaction', $payload['data']['id'], $recur->id);
\Log::debug('Imported ' . $payload['class'] . ' "' . $payload['data']['name'] . '".');
} else {
$this->_repository->store($importMap, 'RecurringTransaction', $payload['data']['id'], $current->id);
\Log::debug('Already had ' . $payload['class'] . ' "' . $payload['data']['description'] . '".');
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importSetting(Job $job, array $payload)
{
switch ($payload['data']['name']) {
default:
$job->delete();
return;
break;
case 'piggyAccount':
// if we have this account, update all piggy banks:
$accountID = intval($payload['data']['value']);
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
$importEntry = $this->_repository->findImportEntry($importMap, 'Account', $accountID);
if ($importEntry) {
$all = $this->_piggybanks->get();
$account = $this->_accounts->find($importEntry->new);
\Log::debug('Updating all piggybanks, found the right setting.');
foreach ($all as $piggy) {
$piggy->account()->associate($account);
unset($piggy->leftInAccount); //??
$piggy->save();
}
} else {
\Log::debug('importSetting wait five minutes and try again...');
$job->release(300);
}
break;
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importTransaction(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// find or create the account type for the import account.
// find or create the account for the import account.
$accountType = $this->_accounts->findAccountType('Import account');
$importAccount = $this->_accounts->createOrFind('Import account', $accountType);
// if amount is more than zero, move from $importAccount
$amount = floatval($payload['data']['amount']);
$accountEntry = $this->_repository->findImportEntry(
$importMap, 'Account',
intval($payload['data']['account_id'])
);
$personalAccount = $this->_accounts->find($accountEntry->new);
if ($amount < 0) {
// if amount is less than zero, move to $importAccount
$accountFrom = $personalAccount;
$accountTo = $importAccount;
} else {
$accountFrom = $importAccount;
$accountTo = $personalAccount;
}
$amount = $amount < 0 ? $amount * -1 : $amount;
$date = new Carbon($payload['data']['date']);
// find a journal?
$current = $this->_repository->findImportEntry($importMap, 'Transaction', intval($payload['data']['id']));
if (is_null($current)) {
$journal = $this->_journals->createSimpleJournal(
$accountFrom, $accountTo,
$payload['data']['description'], $amount, $date
);
$this->_repository->store($importMap, 'Transaction', $payload['data']['id'], $journal->id);
\Log::debug(
'Imported transaction "' . $payload['data']['description'] . '" (' . $journal->date->format('Y-m-d')
. ').'
);
} else {
// do nothing.
\Log::debug('ALREADY imported transaction "' . $payload['data']['description'] . '".');
}
$job->delete();
}
/**
* @param Job $job
* @param array $payload
*/
public function importTransfer(Job $job, array $payload)
{
/** @var \Importmap $importMap */
$importMap = $this->_repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$this->overruleUser($user);
// from account:
$oldFromAccountID = intval($payload['data']['accountfrom_id']);
$oldFromAccountEntry = $this->_repository->findImportEntry($importMap, 'Account', $oldFromAccountID);
$accountFrom = $this->_accounts->find($oldFromAccountEntry->new);
// to account:
$oldToAccountID = intval($payload['data']['accountto_id']);
$oldToAccountEntry = $this->_repository->findImportEntry($importMap, 'Account', $oldToAccountID);
$accountTo = $this->_accounts->find($oldToAccountEntry->new);
if (!is_null($accountFrom) && !is_null($accountTo)) {
$amount = floatval($payload['data']['amount']);
$date = new Carbon($payload['data']['date']);
$journal = $this->_journals->createSimpleJournal(
$accountFrom, $accountTo, $payload['data']['description'],
$amount, $date
);
\Log::debug('Imported transfer "' . $payload['data']['description'] . '".');
$job->delete();
} else {
$job->release(5);
}
}
/**
* @param Job $job
* @param $payload
*/
public function start(Job $job, array $payload)
{
\Log::debug('Start with job "start"');
$user = \User::find($payload['user']);
$filename = $payload['file'];
if (file_exists($filename)) {
// we are able to process the file!
// make an import map. Which is some kind of object because we use queues.
$importMap = new \Importmap;
$importMap->user()->associate($user);
$importMap->file = $filename;
$importMap->save();
// we can now launch a billion jobs importing every little thing into Firefly III
$raw = file_get_contents($filename);
$JSON = json_decode($raw);
$classes = ['accounts', 'components', 'limits', 'piggybanks',
'predictables', 'settings', 'transactions', 'transfers'];
foreach ($classes as $classes_plural) {
$class = ucfirst(\Str::singular($classes_plural));
\Log::debug('Create job to import all ' . $classes_plural);
foreach ($JSON->$classes_plural as $entry) {
\Log::debug('Create job to import single ' . $class);
$fn = 'import' . $class;
$jobFunction = 'Firefly\Queue\Import@' . $fn;
\Queue::push($jobFunction, ['data' => $entry, 'class' => $class, 'mapID' => $importMap->id]);
}
}
// , components, limits, piggybanks, predictables, settings, transactions, transfers
// component_predictables, component_transactions, component_transfers
$count = count($JSON->component_transaction);
foreach ($JSON->component_transaction as $index => $entry) {
\Log::debug('Create job to import components_transaction! Yay! (' . $index . '/' . $count . ') ');
$fn = 'importComponentTransaction';
$jobFunction = 'Firefly\Queue\Import@' . $fn;
\Queue::push($jobFunction, ['data' => $entry, 'mapID' => $importMap->id]);
}
// queue a job to clean up the "import account", it should properly fall back
// to the cash account (which it doesn't always do for some reason).
\Queue::push('Firefly\Queue\Import@cleanImportAccount', ['mapID' => $importMap->id]);
}
\Log::debug('Done with job "start"');
// this is it, close the job:
$job->delete();
}
}

View File

@@ -46,11 +46,23 @@ interface AccountRepositoryInterface
public function find($accountId);
/**
* @param $name
*
* @param $type
* @return mixed
*/
public function findByName($name);
public function findAccountType($type);
/**
* @param $name
* @param \AccountType $type
* @return mixed
*/
public function findByName($name, \AccountType $type = null);
/**
* @param $name
* @return mixed
*/
public function findByNameAny($name);
/**
* @return mixed
@@ -89,6 +101,18 @@ interface AccountRepositoryInterface
*/
public function getDefault();
/**
* @param \AccountType $type
* @return mixed
*/
public function getByAccountType(\AccountType $type);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
/**
* @param $data
*

View File

@@ -12,11 +12,15 @@ use Carbon\Carbon;
*/
class EloquentAccountRepository implements AccountRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
@@ -24,7 +28,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function count()
{
return \Auth::user()->accounts()->count();
return $this->_user->accounts()->count();
}
@@ -86,8 +90,8 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$accountIDs = array_unique($accountIDs);
if (count($accountIDs) > 0) {
// find the "initial balance" type accounts in this list. Should be just 1.
$query = \Auth::user()->accounts()->accountTypeIn(['Initial balance account'])
->whereIn('accounts.id', $accountIDs);
$query = $this->_user->accounts()->accountTypeIn(['Initial balance account'])
->whereIn('accounts.id', $accountIDs);
if ($query->count() == 1) {
$iba = $query->first(['accounts.*']);
$iba->delete();
@@ -111,7 +115,16 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function find($accountId)
{
return \Auth::user()->accounts()->where('id', $accountId)->first();
return $this->_user->accounts()->where('id', $accountId)->first();
}
/**
* @param $type
* @return mixed
*/
public function findAccountType($type)
{
return \AccountType::where('type', $type)->first();
}
/**
@@ -124,9 +137,23 @@ class EloquentAccountRepository implements AccountRepositoryInterface
{
$type = is_null($type) ? \AccountType::where('type', 'Default account')->first() : $type;
return \Auth::user()->accounts()->where('account_type_id', $type->id)
->where('name', 'like', '%' . $name . '%')
->first();
return $this->_user->accounts()->where('account_type_id', $type->id)
->where('name', 'like', '%' . $name . '%')
->first();
}
/**
* Used for import
*
* @param $name
*
* @return mixed
*/
public function findByNameAny($name)
{
return $this->_user->accounts()
->where('name', 'like', '%' . $name . '%')
->first();
}
/**
@@ -134,7 +161,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function get()
{
return \Auth::user()->accounts()->with('accounttype')->orderBy('name', 'ASC')->get();
return $this->_user->accounts()->with('accounttype')->orderBy('name', 'ASC')->get();
}
/**
@@ -142,10 +169,10 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function getActiveDefault()
{
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.type', 'Default account')->where('accounts.active', 1)
return $this->_user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.type', 'Default account')->where('accounts.active', 1)
->get(['accounts.*']);
->get(['accounts.*']);
}
/**
@@ -153,12 +180,12 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function getActiveDefaultAsSelectList()
{
$list = \Auth::user()->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id'
$list = $this->_user->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id'
)
->where('account_types.type', 'Default account')->where('accounts.active', 1)
->where('account_types.type', 'Default account')->where('accounts.active', 1)
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$return = [];
foreach ($list as $entry) {
$return[intval($entry->id)] = $entry->name;
@@ -172,16 +199,22 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function getBeneficiaries()
{
$list = \Auth::user()->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id'
$list = $this->_user->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id'
)
->where('account_types.type', 'Beneficiary account')->where('accounts.active', 1)
->where('account_types.type', 'Beneficiary account')->where('accounts.active', 1)
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
return $list;
}
public function getByAccountType(\AccountType $type)
{
return $this->_user->accounts()->with('accounttype')->orderBy('name', 'ASC')
->where('account_type_id', $type->id)->get();
}
/**
* @param $ids
*
@@ -190,7 +223,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function getByIds(array $ids)
{
if (count($ids) > 0) {
return \Auth::user()->accounts()->with('accounttype')->whereIn('id', $ids)->orderBy('name', 'ASC')->get();
return $this->_user->accounts()->with('accounttype')->whereIn('id', $ids)->orderBy('name', 'ASC')->get();
} else {
return $this->getActiveDefault();
}
@@ -202,7 +235,15 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function getCashAccount()
{
$type = \AccountType::where('type', 'Cash account')->first();
$cash = \Auth::user()->accounts()->where('account_type_id', $type->id)->first();
$cash = $this->_user->accounts()->where('account_type_id', $type->id)->first();
if (is_null($cash)) {
$cash = new \Account;
$cash->accountType()->associate($type);
$cash->user()->associate($this->_user);
$cash->name = 'Cash account';
$cash->active = 1;
$cash->save();
}
return $cash;
@@ -213,10 +254,20 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
public function getDefault()
{
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.type', 'Default account')
return $this->_user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.type', 'Default account')
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
/**
@@ -234,6 +285,9 @@ class EloquentAccountRepository implements AccountRepositoryInterface
&& get_class($data['account_type']) == 'AccountType'
) {
$accountType = $data['account_type'];
} else if (isset($data['account_type']) && is_string($data['account_type'])) {
$accountType = \AccountType::where('type', $data['account_type'])->first();
} else {
$accountType = \AccountType::where('type', 'Default account')->first();
}
@@ -243,7 +297,8 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/
$account = new \Account;
$account->accountType()->associate($accountType);
$account->user()->associate(\Auth::user());
$account->user()->associate($this->_user);
$account->name = $data['name'];
$account->active
= isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval(
@@ -256,7 +311,9 @@ class EloquentAccountRepository implements AccountRepositoryInterface
if (isset($data['openingbalance']) && isset($data['openingbalancedate'])) {
$amount = floatval($data['openingbalance']);
$date = new Carbon($data['openingbalancedate']);
$this->_createInitialBalance($account, $amount, $date);
if ($amount != 0) {
$this->_createInitialBalance($account, $amount, $date);
}
}
}
@@ -318,7 +375,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
// create new account:
$initial = new \Account;
$initial->accountType()->associate($initialBalanceAT);
$initial->user()->associate(\Auth::user());
$initial->user()->associate($this->_user);
$initial->name = $account->name . ' initial balance';
$initial->active = 0;
if ($initial->validate()) {
@@ -328,6 +385,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$transactionJournal = \App::make(
'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'
);
$transactionJournal->overruleUser($this->_user);
$transactionJournal->createSimpleJournal(
$initial, $account, 'Initial Balance for ' . $account->name, $amount, $date

View File

@@ -23,6 +23,19 @@ interface BudgetRepositoryInterface
*/
public function find($budgetId);
/**
* @param $budgetName
* @return mixed
*/
public function findByName($budgetName);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
/**
* @return mixed
*/

View File

@@ -3,19 +3,32 @@
namespace Firefly\Storage\Budget;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
/**
* Class EloquentBudgetRepository
*
* @package Firefly\Storage\Budget
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*
*/
class EloquentBudgetRepository implements BudgetRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @param \Budget $budget
*
* @return bool|mixed
* @return bool
*/
public function destroy(\Budget $budget)
{
@@ -27,25 +40,35 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface
/**
* @param $budgetId
*
* @return mixed
* @return \Budget|null
*/
public function find($budgetId)
{
return \Auth::user()->budgets()->find($budgetId);
return $this->_user->budgets()->find($budgetId);
}
/**
* @return mixed
* @param $budgetName
* @return \Budget|null
*/
public function findByName($budgetName)
{
return $this->_user->budgets()->whereName($budgetName)->first();
}
/**
* @return Collection
*/
public function get()
{
$set = \Auth::user()->budgets()->with(
['limits' => function ($q) {
$q->orderBy('limits.startdate', 'DESC');
}, 'limits.limitrepetitions' => function ($q) {
$q->orderBy('limit_repetitions.startdate', 'ASC');
}]
$set = $this->_user->budgets()->with(
['limits' => function ($q) {
$q->orderBy('limits.startdate', 'DESC');
}, 'limits.limitrepetitions' => function ($q) {
$q->orderBy('limit_repetitions.startdate', 'ASC');
}]
)->orderBy('name', 'ASC')->get();
foreach ($set as $budget) {
foreach ($budget->limits as $limit) {
@@ -59,12 +82,12 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface
}
/**
* @return array|mixed
* @return array
*/
public function getAsSelectList()
{
$list = \Auth::user()->budgets()->with(
['limits', 'limits.limitrepetitions']
$list = $this->_user->budgets()->with(
['limits', 'limits.limitrepetitions']
)->orderBy('name', 'ASC')->get();
$return = [];
foreach ($list as $entry) {
@@ -74,56 +97,45 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface
return $return;
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
/**
* @param $data
*
* @return \Budget|mixed
* @return \Budget
*/
public function store($data)
{
$budget = new \Budget;
$budget = new \Budget;
$budget->name = $data['name'];
$budget->user()->associate(\Auth::user());
$budget->user()->associate($this->_user);
$budget->save();
// if limit, create limit (repetition itself will be picked up elsewhere).
if (floatval($data['amount']) > 0) {
$limit = new \Limit;
$limit->budget()->associate($budget);
if (isset($data['amount']) && floatval($data['amount']) > 0) {
$startDate = new Carbon;
switch ($data['repeat_freq']) {
case 'daily':
$startDate->startOfDay();
break;
case 'weekly':
$startDate->startOfWeek();
break;
case 'monthly':
$startDate->startOfMonth();
break;
case 'quarterly':
$startDate->firstOfQuarter();
break;
case 'half-year':
$startDate->startOfYear();
if (intval($startDate->format('m')) >= 7) {
$startDate->addMonths(6);
}
break;
case 'yearly':
$startDate->startOfYear();
break;
}
$limit->startdate = $startDate;
$limit->amount = $data['amount'];
$limit->repeats = isset($data['repeats']) ? $data['repeats'] : 0;
$limit->repeat_freq = $data['repeat_freq'];
if ($limit->validate()) {
$limit->save();
\Event::fire('limits.store', [$limit]);
}
$limitData = [
'budget_id' => $budget->id,
'startdate' => $startDate->format('Y-m-d'),
'period' => $data['repeat_freq'],
'amount' => floatval($data['amount']),
'repeats' => 0
];
/** @var \Firefly\Storage\Limit\LimitRepositoryInterface $limitRepository */
$limitRepository = \App::make('Firefly\Storage\Limit\LimitRepositoryInterface');
$limitRepository->overruleUser($this->_user);
$limit = $limitRepository->store($limitData);
\Event::fire('limits.store', [$limit]);
}
if ($budget->validate()) {
$budget->save();
}

View File

@@ -29,6 +29,12 @@ interface CategoryRepositoryInterface
*/
public function createOrFind($name);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
/**
* @param $name
*

View File

@@ -9,6 +9,16 @@ namespace Firefly\Storage\Category;
*/
class EloquentCategoryRepository implements CategoryRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @param $name
*
@@ -48,7 +58,7 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface
*/
public function find($categoryId)
{
return \Auth::user()->categories()->find($categoryId);
return $this->_user->categories()->find($categoryId);
}
/**
@@ -62,7 +72,7 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface
return null;
}
return \Auth::user()->categories()->where('name', 'LIKE', '%' . $name . '%')->first();
return $this->_user->categories()->where('name', 'LIKE', '%' . $name . '%')->first();
}
@@ -71,7 +81,7 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface
*/
public function get()
{
return \Auth::user()->categories()->orderBy('name', 'ASC')->get();
return $this->_user->categories()->orderBy('name', 'ASC')->get();
}
/**
@@ -81,10 +91,10 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface
*/
public function store($data)
{
$category = new \Category;
$category = new \Category;
$category->name = $data['name'];
$category->user()->associate(\Auth::user());
$category->user()->associate($this->_user);
$category->save();
return $category;
@@ -106,4 +116,14 @@ class EloquentCategoryRepository implements CategoryRepositoryInterface
return $category;
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
}

View File

@@ -28,4 +28,10 @@ interface ComponentRepositoryInterface
*/
public function store($data);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
}

View File

@@ -14,12 +14,14 @@ use Illuminate\Database\QueryException;
class EloquentComponentRepository implements ComponentRepositoryInterface
{
public $validator;
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
@@ -27,7 +29,7 @@ class EloquentComponentRepository implements ComponentRepositoryInterface
*/
public function count()
{
return \Auth::user()->components()->count();
return $this->_user->components()->count();
}
@@ -40,6 +42,16 @@ class EloquentComponentRepository implements ComponentRepositoryInterface
throw new FireflyException('No implementation.');
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
/**
* @param $data
*
@@ -62,7 +74,7 @@ class EloquentComponentRepository implements ComponentRepositoryInterface
}
$component->name = $data['name'];
$component->user()->associate(\Auth::user());
$component->user()->associate($this->_user);
try {
$component->save();
} catch (QueryException $e) {

View File

@@ -0,0 +1,58 @@
<?php
namespace Firefly\Storage\Import;
class EloquentImportRepository implements ImportRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
public function findImportComponentMap(\Importmap $map, $oldComponentId)
{
$entry = \Importentry::where('importmap_id', $map->id)
->whereIn('class', ['Budget', 'Category', 'Account', 'Component'])
->where('old', intval($oldComponentId))->first();
return $entry;
}
public function findImportEntry(\Importmap $map, $class, $oldID)
{
return \Importentry::where('importmap_id', $map->id)->where('class', $class)->where('old', $oldID)->first();
}
public function findImportMap($id)
{
return \Importmap::find($id);
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
public function store(\Importmap $map, $class, $oldID, $newID)
{
$entry = new \Importentry;
$entry->importmap()->associate($map);
$entry->class = $class;
$entry->old = intval($oldID);
$entry->new = intval($newID);
$entry->save();
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Firefly\Storage\Import;
/**
* Interface ImportRepositoryInterface
* @package Firefly\Storage\Import
*/
interface ImportRepositoryInterface
{
/**
* @param \Importmap $map
* @param $class
* @param $oldID
* @param $newID
* @return mixed
*/
public function store(\Importmap $map, $class, $oldID, $newID);
public function findImportMap($id);
public function findImportEntry(\Importmap $map, $class, $oldID);
public function findImportComponentMap(\Importmap $map, $oldComponentId);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
}

View File

@@ -12,7 +12,15 @@ use Carbon\Carbon;
*/
class EloquentLimitRepository implements LimitRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @param \Limit $limit
@@ -26,24 +34,6 @@ class EloquentLimitRepository implements LimitRepositoryInterface
return true;
}
/**
* @param \Limit $limit
* @param $data
*
* @return mixed|void
*/
public function update(\Limit $limit, $data)
{
$limit->startdate = new Carbon($data['startdate']);
$limit->repeat_freq = $data['period'];
$limit->repeats = isset($data['repeats']) && $data['repeats'] == '1' ? 1 : 0;
$limit->amount = floatval($data['amount']);
$limit->save();
return $limit;
}
/**
* @param $limitId
*
@@ -52,15 +42,20 @@ class EloquentLimitRepository implements LimitRepositoryInterface
public function find($limitId)
{
return \Limit::with('limitrepetitions')->where('limits.id', $limitId)->leftJoin(
'components', 'components.id', '=', 'limits.component_id'
'components', 'components.id', '=', 'limits.component_id'
)
->where('components.user_id', \Auth::user()->id)->first(['limits.*']);
->where('components.user_id', $this->_user->id)->first(['limits.*']);
}
public function findByBudgetAndDate(\Budget $budget, Carbon $date)
{
return \Limit::whereComponentId($budget->id)->where('startdate', $date->format('Y-m-d'))->first();
}
/**
* @param \Budget $budget
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
@@ -72,6 +67,16 @@ class EloquentLimitRepository implements LimitRepositoryInterface
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
/**
* @param $data
*
@@ -116,9 +121,9 @@ class EloquentLimitRepository implements LimitRepositoryInterface
// find existing:
$count = \Limit::
leftJoin('components', 'components.id', '=', 'limits.component_id')->where(
'components.user_id', \Auth::user()->id
'components.user_id', $this->_user->id
)->where('startdate', $date->format('Y-m-d'))->where('component_id', $data['budget_id'])->where(
'repeat_freq', $data['period']
'repeat_freq', $data['period']
)->count();
if ($count > 0) {
\Session::flash('error', 'There already is an entry for these parameters.');
@@ -128,9 +133,9 @@ class EloquentLimitRepository implements LimitRepositoryInterface
// create new limit:
$limit = new \Limit;
$limit->budget()->associate($budget);
$limit->startdate = $date;
$limit->amount = floatval($data['amount']);
$limit->repeats = isset($data['repeats']) ? intval($data['repeats']) : 0;
$limit->startdate = $date;
$limit->amount = floatval($data['amount']);
$limit->repeats = isset($data['repeats']) ? intval($data['repeats']) : 0;
$limit->repeat_freq = $data['period'];
if (!$limit->save()) {
\Session::flash('error', 'Could not save: ' . $limit->errors()->first());
@@ -139,4 +144,22 @@ class EloquentLimitRepository implements LimitRepositoryInterface
return $limit;
}
/**
* @param \Limit $limit
* @param $data
*
* @return mixed|void
*/
public function update(\Limit $limit, $data)
{
$limit->startdate = new Carbon($data['startdate']);
$limit->repeat_freq = $data['period'];
$limit->repeats = isset($data['repeats']) && $data['repeats'] == '1' ? 1 : 0;
$limit->amount = floatval($data['amount']);
$limit->save();
return $limit;
}
}

View File

@@ -12,6 +12,36 @@ use Carbon\Carbon;
interface LimitRepositoryInterface
{
/**
* @param \Limit $limit
*
* @return mixed
*/
public function destroy(\Limit $limit);
/**
* @param $limitId
*
* @return mixed
*/
public function find($limitId);
/**
* @param \Budget $budget
* @param Carbon $date
* @return mixed
*/
public function findByBudgetAndDate(\Budget $budget, Carbon $date);
/**
* @param \Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getTJByBudgetAndDateRange(\Budget $budget, Carbon $start, Carbon $end);
/**
* @param $data
*
@@ -28,25 +58,8 @@ interface LimitRepositoryInterface
public function update(\Limit $limit, $data);
/**
* @param \Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @param \User $user
* @return mixed
*/
public function getTJByBudgetAndDateRange(\Budget $budget, Carbon $start, Carbon $end);
/**
* @param $limitId
*
* @return mixed
*/
public function find($limitId);
/**
* @param \Limit $limit
*
* @return mixed
*/
public function destroy(\Limit $limit);
public function overruleUser(\User $user);
}

View File

@@ -14,6 +14,15 @@ use Firefly\Exception\FireflyException;
class EloquentPiggybankRepository implements PiggybankRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @return mixed
@@ -21,14 +30,14 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
public function count()
{
return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where(
'accounts.user_id', \Auth::user()->id
'accounts.user_id', $this->_user->id
)->count();
}
public function countNonrepeating()
{
return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where(
'accounts.user_id', \Auth::user()->id
'accounts.user_id', $this->_user->id
)->where('repeats', 0)->count();
}
@@ -36,7 +45,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
public function countRepeating()
{
return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where(
'accounts.user_id', \Auth::user()->id
'accounts.user_id', $this->_user->id
)->where('repeats', 1)->count();
}
@@ -60,16 +69,23 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
public function find($piggyBankId)
{
return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where(
'accounts.user_id', \Auth::user()->id
'accounts.user_id', $this->_user->id
)->where('piggybanks.id', $piggyBankId)->first(['piggybanks.*']);
}
public function findByName($piggyBankName)
{
return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where(
'accounts.user_id', $this->_user->id
)->where('piggybanks.name', $piggyBankName)->first(['piggybanks.*']);
}
/**
* @return mixed
*/
public function get()
{
$piggies = \Auth::user()->piggybanks()->with(['account', 'piggybankrepetitions'])->get();
$piggies = $this->_user->piggybanks()->with(['account', 'piggybankrepetitions'])->get();
foreach ($piggies as $pig) {
$pig->leftInAccount = $this->leftOnAccount($pig->account);
@@ -95,7 +111,6 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
}
/**
* @param \Piggybank $piggyBank
* @param $amount
@@ -115,6 +130,16 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
/**
* @param $data
*
@@ -122,19 +147,20 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
*/
public function store($data)
{
if ($data['targetdate'] == '') {
if (isset($data['targetdate']) && $data['targetdate'] == '') {
unset($data['targetdate']);
}
if ($data['reminder'] == 'none') {
if (isset($data['reminder']) && $data['reminder'] == 'none') {
unset($data['reminder']);
}
if ($data['startdate'] == '') {
if (isset($data['startdate']) && $data['startdate'] == '') {
unset($data['startdate']);
}
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null;
$accounts->overruleUser($this->_user);
$account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null;
$piggyBank = new \Piggybank($data);
@@ -142,7 +168,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
if (!is_null($piggyBank->reminder) && is_null($piggyBank->startdate) && is_null($piggyBank->targetdate)) {
$piggyBank->errors()->add('reminder', 'Cannot create reminders without start ~ AND target date.');
\Log::error('PiggyBank create-error: ' . $piggyBank->errors()->first());
return $piggyBank;
}
@@ -150,6 +176,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
if ($piggyBank->repeats && !isset($data['targetdate'])) {
$piggyBank->errors()->add('targetdate', 'Target date is mandatory!');
\Log::error('PiggyBank create-error: ' . $piggyBank->errors()->first());
return $piggyBank;
}
@@ -161,13 +188,14 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
if ($piggyBank->validate()) {
if (!is_null($piggyBank->targetdate) && $piggyBank->targetdate < $today) {
$piggyBank->errors()->add('targetdate', 'Target date cannot be in the past.');
\Log::error('PiggyBank create-error: ' . $piggyBank->errors()->first());
return $piggyBank;
}
if (!is_null($piggyBank->reminder) && !is_null($piggyBank->targetdate)) {
// first period for reminder is AFTER target date.
$reminderSkip = $piggyBank->reminder_skip < 1 ? 1 : intval($piggyBank->reminder_skip);
$reminderSkip = $piggyBank->reminder_skip < 1 ? 1 : intval($piggyBank->reminder_skip);
$firstReminder = new Carbon;
switch ($piggyBank->reminder) {
case 'day':
@@ -188,8 +216,9 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
}
if ($firstReminder > $piggyBank->targetdate) {
$piggyBank->errors()->add(
'reminder', 'The reminder has been set to remind you after the piggy bank will expire.'
'reminder', 'The reminder has been set to remind you after the piggy bank will expire.'
);
\Log::error('PiggyBank create-error: ' . $piggyBank->errors()->first());
return $piggyBank;
}
@@ -197,6 +226,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
$piggyBank->save();
}
return $piggyBank;
}
@@ -210,19 +240,20 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
{
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null;
$accounts->overruleUser($this->_user);
$account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null;
if (!is_null($account)) {
$piggy->account()->associate($account);
}
$piggy->name = $data['name'];
$piggy->targetamount = floatval($data['targetamount']);
$piggy->reminder = isset($data['reminder']) && $data['reminder'] != 'none' ? $data['reminder'] : null;
$piggy->name = $data['name'];
$piggy->targetamount = floatval($data['targetamount']);
$piggy->reminder = isset($data['reminder']) && $data['reminder'] != 'none' ? $data['reminder'] : null;
$piggy->reminder_skip = $data['reminder_skip'];
$piggy->targetdate = strlen($data['targetdate']) > 0 ? new Carbon($data['targetdate']) : null;
$piggy->targetdate = strlen($data['targetdate']) > 0 ? new Carbon($data['targetdate']) : null;
$piggy->startdate
= isset($data['startdate']) && strlen($data['startdate']) > 0 ? new Carbon($data['startdate']) : null;
= isset($data['startdate']) && strlen($data['startdate']) > 0 ? new Carbon($data['startdate']) : null;
foreach ($piggy->piggybankrepetitions()->get() as $rep) {
@@ -230,7 +261,7 @@ class EloquentPiggybankRepository implements PiggybankRepositoryInterface
}
if ($piggy->repeats == 1) {
$piggy->rep_every = intval($data['rep_every']);
$piggy->rep_every = intval($data['rep_every']);
$piggy->rep_length = $data['rep_length'];
}

View File

@@ -40,6 +40,8 @@ interface PiggybankRepositoryInterface
*/
public function find($piggyBankId);
public function findByName($piggyBankName);
/**
* @return mixed
*/
@@ -77,5 +79,11 @@ interface PiggybankRepositoryInterface
*/
public function update(\Piggybank $piggy, $data);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
}

View File

@@ -12,6 +12,27 @@ use Carbon\Carbon;
*/
class EloquentRecurringTransactionRepository implements RecurringTransactionRepositoryInterface
{
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @param \RecurringTransaction $recurringTransaction
*
@@ -24,12 +45,17 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
return true;
}
public function findByName($name)
{
return $this->_user->recurringtransactions()->where('name', 'LIKE', '%' . $name . '%')->first();
}
/**
* @return mixed
*/
public function get()
{
return \Auth::user()->recurringtransactions()->get();
return $this->_user->recurringtransactions()->get();
}
/**
@@ -40,9 +66,9 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
public function store($data)
{
$recurringTransaction = new \RecurringTransaction;
$recurringTransaction->user()->associate(\Auth::user());
$recurringTransaction->name = $data['name'];
$recurringTransaction->match = join(' ', explode(',', $data['match']));
$recurringTransaction->user()->associate($this->_user);
$recurringTransaction->name = $data['name'];
$recurringTransaction->match = join(' ', explode(',', $data['match']));
$recurringTransaction->amount_max = floatval($data['amount_max']);
$recurringTransaction->amount_min = floatval($data['amount_min']);
@@ -53,10 +79,10 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
return $recurringTransaction;
}
$recurringTransaction->date = new Carbon($data['date']);
$recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0;
$recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0;
$recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0;
$recurringTransaction->date = new Carbon($data['date']);
$recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0;
$recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0;
$recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0;
$recurringTransaction->repeat_freq = $data['repeat_freq'];
if ($recurringTransaction->validate()) {
@@ -74,8 +100,8 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
*/
public function update(\RecurringTransaction $recurringTransaction, $data)
{
$recurringTransaction->name = $data['name'];
$recurringTransaction->match = join(' ', explode(',', $data['match']));
$recurringTransaction->name = $data['name'];
$recurringTransaction->match = join(' ', explode(',', $data['match']));
$recurringTransaction->amount_max = floatval($data['amount_max']);
$recurringTransaction->amount_min = floatval($data['amount_min']);
@@ -85,10 +111,10 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
return $recurringTransaction;
}
$recurringTransaction->date = new Carbon($data['date']);
$recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0;
$recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0;
$recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0;
$recurringTransaction->date = new Carbon($data['date']);
$recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0;
$recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0;
$recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0;
$recurringTransaction->repeat_freq = $data['repeat_freq'];
if ($recurringTransaction->validate()) {

View File

@@ -16,6 +16,12 @@ interface RecurringTransactionRepositoryInterface
*/
public function get();
/**
* @param $name
* @return mixed
*/
public function findByName($name);
/**
* @param $data
*
@@ -38,5 +44,11 @@ interface RecurringTransactionRepositoryInterface
*/
public function update(\RecurringTransaction $recurringTransaction, $data);
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
}

View File

@@ -12,6 +12,26 @@ use Carbon\Carbon;
*/
class EloquentReminderRepository implements ReminderRepositoryInterface
{
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @param \Reminder $reminder
*
@@ -42,7 +62,7 @@ class EloquentReminderRepository implements ReminderRepositoryInterface
{
$today = new Carbon;
return \Auth::user()->reminders()->validOn($today)->get();
return $this->_user->reminders()->validOn($today)->get();
}
/**
@@ -52,8 +72,8 @@ class EloquentReminderRepository implements ReminderRepositoryInterface
{
$today = new Carbon;
return \Auth::user()->reminders()->with('recurringtransaction')->validOn($today)->where(
'class', 'RecurringTransactionReminder'
return $this->_user->reminders()->with('recurringtransaction')->validOn($today)->where(
'class', 'RecurringTransactionReminder'
)->get();
}

View File

@@ -39,4 +39,10 @@ interface ReminderRepositoryInterface
public function getCurrentRecurringReminders();
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
}

View File

@@ -18,55 +18,60 @@ class StorageServiceProvider extends ServiceProvider
public function register()
{
$this->app->bind(
'Firefly\Storage\User\UserRepositoryInterface',
'Firefly\Storage\User\EloquentUserRepository'
'Firefly\Storage\User\UserRepositoryInterface',
'Firefly\Storage\User\EloquentUserRepository'
);
$this->app->bind(
'Firefly\Storage\Transaction\TransactionRepositoryInterface',
'Firefly\Storage\Transaction\EloquentTransactionRepository'
'Firefly\Storage\Transaction\TransactionRepositoryInterface',
'Firefly\Storage\Transaction\EloquentTransactionRepository'
);
$this->app->bind(
'Firefly\Storage\Import\ImportRepositoryInterface',
'Firefly\Storage\Import\EloquentImportRepository'
);
$this->app->bind(
'Firefly\Storage\Piggybank\PiggybankRepositoryInterface',
'Firefly\Storage\Piggybank\EloquentPiggybankRepository'
);
$this->app->bind(
'Firefly\Storage\Piggybank\PiggybankRepositoryInterface',
'Firefly\Storage\Piggybank\EloquentPiggybankRepository'
'Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface',
'Firefly\Storage\RecurringTransaction\EloquentRecurringTransactionRepository'
);
$this->app->bind(
'Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface',
'Firefly\Storage\RecurringTransaction\EloquentRecurringTransactionRepository'
'Firefly\Storage\Reminder\ReminderRepositoryInterface',
'Firefly\Storage\Reminder\EloquentReminderRepository'
);
$this->app->bind(
'Firefly\Storage\Reminder\ReminderRepositoryInterface',
'Firefly\Storage\Reminder\EloquentReminderRepository'
'Firefly\Storage\Account\AccountRepositoryInterface',
'Firefly\Storage\Account\EloquentAccountRepository'
);
$this->app->bind(
'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface',
'Firefly\Storage\TransactionJournal\EloquentTransactionJournalRepository'
);
$this->app->bind(
'Firefly\Storage\Account\AccountRepositoryInterface',
'Firefly\Storage\Account\EloquentAccountRepository'
);
$this->app->bind(
'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface',
'Firefly\Storage\TransactionJournal\EloquentTransactionJournalRepository'
'Firefly\Storage\Component\ComponentRepositoryInterface',
'Firefly\Storage\Component\EloquentComponentRepository'
);
$this->app->bind(
'Firefly\Storage\Component\ComponentRepositoryInterface',
'Firefly\Storage\Component\EloquentComponentRepository'
'Firefly\Storage\Limit\LimitRepositoryInterface',
'Firefly\Storage\Limit\EloquentLimitRepository'
);
$this->app->bind(
'Firefly\Storage\Limit\LimitRepositoryInterface',
'Firefly\Storage\Limit\EloquentLimitRepository'
);
$this->app->bind(
'Firefly\Storage\Budget\BudgetRepositoryInterface',
'Firefly\Storage\Budget\EloquentBudgetRepository'
'Firefly\Storage\Budget\BudgetRepositoryInterface',
'Firefly\Storage\Budget\EloquentBudgetRepository'
);
$this->app->bind(
'Firefly\Storage\Category\CategoryRepositoryInterface',
'Firefly\Storage\Category\EloquentCategoryRepository'
'Firefly\Storage\Category\CategoryRepositoryInterface',
'Firefly\Storage\Category\EloquentCategoryRepository'
);
}

View File

@@ -9,5 +9,24 @@ namespace Firefly\Storage\Transaction;
*/
class EloquentTransactionRepository implements TransactionRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
}

View File

@@ -9,6 +9,11 @@ namespace Firefly\Storage\Transaction;
*/
interface TransactionRepositoryInterface
{
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
}

View File

@@ -14,6 +14,16 @@ use Firefly\Exception\FireflyException;
class EloquentTransactionJournalRepository implements TransactionJournalRepositoryInterface
{
protected $_user = null;
/**
*
*/
public function __construct()
{
$this->_user = \Auth::user();
}
/**
*
* We're building this thinking the money goes from A to B.
@@ -34,8 +44,8 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
* A gains 200 (200). * -1
* B loses 200 (-200). * 1
*
* @param \Account $from
* @param \Account $toAccount
* @param \Account $from
* @param \Account $toAccount
* @param $description
* @param $amount
* @param \Carbon\Carbon $date
@@ -48,7 +58,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$journal = new \TransactionJournal;
$amountFrom = $amount * -1;
$amountTo = $amount;
$amountTo = $amount;
if (round(floatval($amount), 2) == 0.00) {
$journal->errors()->add('amount', 'Amount must not be zero.');
@@ -64,7 +74,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
}
// account types for both:
$toAT = $toAccount->accountType->type;
$toAT = $toAccount->accountType->type;
$fromAT = $from->accountType->type;
$journalType = null;
@@ -105,10 +115,10 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$journal->transactionType()->associate($journalType);
$journal->transactionCurrency()->associate($currency);
$journal->user()->associate(\Auth::user());
$journal->completed = false;
$journal->user()->associate($this->_user);
$journal->completed = false;
$journal->description = $description;
$journal->date = $date;
$journal->date = $date;
if (!$journal->validate()) {
return $journal;
}
@@ -119,10 +129,10 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$fromTransaction->account()->associate($from);
$fromTransaction->transactionJournal()->associate($journal);
$fromTransaction->description = null;
$fromTransaction->amount = $amountFrom;
$fromTransaction->amount = $amountFrom;
if (!$fromTransaction->validate()) {
throw new FireflyException('Cannot create valid transaction (from): ' . $fromTransaction->errors()->first(
));
throw new FireflyException('Cannot create valid transaction (from): ' . $fromTransaction->errors()
->first());
}
$fromTransaction->save();
@@ -130,7 +140,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$toTransaction->account()->associate($toAccount);
$toTransaction->transactionJournal()->associate($journal);
$toTransaction->description = null;
$toTransaction->amount = $amountTo;
$toTransaction->amount = $amountTo;
if (!$toTransaction->validate()) {
throw new FireflyException('Cannot create valid transaction (to): ' . $toTransaction->errors()->first());
}
@@ -149,13 +159,13 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
*/
public function find($journalId)
{
return \Auth::user()->transactionjournals()->with(
['transactions' => function ($q) {
return $q->orderBy('amount', 'ASC');
}, 'transactioncurrency', 'transactiontype', 'components', 'transactions.account',
'transactions.account.accounttype']
return $this->_user->transactionjournals()->with(
['transactions' => function ($q) {
return $q->orderBy('amount', 'ASC');
}, 'transactioncurrency', 'transactiontype', 'components', 'transactions.account',
'transactions.account.accounttype']
)
->where('id', $journalId)->first();
->where('id', $journalId)->first();
}
/**
@@ -168,64 +178,76 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
/**
* @param \Account $account
* @param Carbon $date
* @param Carbon $date
*
* @return mixed
*/
public function getByAccountAndDate(\Account $account, Carbon $date)
{
$accountID = $account->id;
$query = \Auth::user()->transactionjournals()->with(
[
'transactions',
'transactions.account',
'transactioncurrency',
'transactiontype'
]
$query = $this->_user->transactionjournals()->with(
[
'transactions',
'transactions.account',
'transactioncurrency',
'transactiontype'
]
)
->distinct()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->where('transactions.account_id', $accountID)
->where('transaction_journals.date', $date->format('Y-m-d'))
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->get(['transaction_journals.*']);
->distinct()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=',
'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->where('transactions.account_id', $accountID)
->where('transaction_journals.date', $date->format('Y-m-d'))
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->get(['transaction_journals.*']);
return $query;
}
/**
* @param \Account $account
* @param int $count
* @param Carbon $start
* @param Carbon $end
* @param int $count
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getByAccountInDateRange(\Account $account, $count = 25, Carbon $start, Carbon $end)
{
$accountID = $account->id;
$query = \Auth::user()->transactionjournals()->with(
[
'transactions',
'transactioncurrency',
'transactiontype'
]
$query = $this->_user->transactionjournals()->with(
[
'transactions',
'transactioncurrency',
'transactiontype'
]
)
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->where('accounts.id', $accountID)
->where('date', '>=', $start->format('Y-m-d'))
->where('date', '<=', $end->format('Y-m-d'))
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->take($count)
->get(['transaction_journals.*']);
->leftJoin('transactions', 'transactions.transaction_journal_id', '=',
'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->where('accounts.id', $accountID)
->where('date', '>=', $start->format('Y-m-d'))
->where('date', '<=', $end->format('Y-m-d'))
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->take($count)
->get(['transaction_journals.*']);
return $query;
}
/**
* @param \User $user
* @return mixed|void
*/
public function overruleUser(\User $user)
{
$this->_user = $user;
return true;
}
/**
* @param int $count
*
@@ -233,19 +255,9 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
*/
public function paginate($count = 25, Carbon $start = null, Carbon $end = null)
{
$query = \Auth::user()->transactionjournals()->with(
[
'transactions' => function ($q) {
return $q->orderBy('amount', 'ASC');
},
'transactions.account',
'transactions.account.accounttype',
'transactioncurrency',
'transactiontype'
]
)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC');
$query = $this->_user->transactionjournals()->WithRelevantData()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC');
if (!is_null($start)) {
$query->where('transaction_journals.date', '>=', $start->format('Y-m-d'));
}
@@ -270,37 +282,40 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
// depending on the $what
$fromAccount = null;
$toAccount = null;
$toAccount = null;
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */
$accountRepository = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$accountRepository->overruleUser($this->_user);
/** @var \Firefly\Storage\Category\CategoryRepositoryInterface $catRepository */
$catRepository = \App::make('Firefly\Storage\Category\CategoryRepositoryInterface');
$catRepository->overruleUser($this->_user);
/** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budRepository */
$budRepository = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
$budRepository->overruleUser($this->_user);
switch ($what) {
case 'withdrawal':
$fromAccount = $accountRepository->find(intval($data['account_id']));
$toAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
$toAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
break;
case 'deposit':
$fromAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
$toAccount = $accountRepository->find(intval($data['account_id']));
$toAccount = $accountRepository->find(intval($data['account_id']));
break;
case 'transfer':
$fromAccount = $accountRepository->find(intval($data['account_from_id']));
$toAccount = $accountRepository->find(intval($data['account_to_id']));
$toAccount = $accountRepository->find(intval($data['account_to_id']));
break;
}
// fall back to cash if necessary:
$fromAccount = is_null($fromAccount) ? $fromAccount = $accountRepository->getCashAccount() : $fromAccount;
$toAccount = is_null($toAccount) ? $toAccount = $accountRepository->getCashAccount() : $toAccount;
$toAccount = is_null($toAccount) ? $toAccount = $accountRepository->getCashAccount() : $toAccount;
// create or find category:
$category = isset($data['category']) ? $catRepository->createOrFind($data['category']) : null;
@@ -309,8 +324,8 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$budget = isset($data['budget_id']) ? $budRepository->find(intval($data['budget_id'])) : null;
// find amount & description:
$description = trim($data['description']);
$amount = floatval($data['amount']);
$date = new Carbon($data['date']);
$amount = floatval($data['amount']);
$date = new Carbon($data['date']);
// try to create a journal:
$transactionJournal = $this->createSimpleJournal($fromAccount, $toAccount, $description, $amount, $date);
@@ -323,6 +338,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
if ($what == 'transfer') {
/** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */
$piggyRepository = \App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
$piggyRepository->overruleUser($this->_user);
if (isset($data['piggybank_id'])) {
/** @var \Piggybank $piggyBank */
@@ -337,15 +353,15 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$transaction->piggybank()->associate($piggyBank);
$transaction->save();
\Event::fire(
'piggybanks.createRelatedTransfer', [$piggyBank, $transactionJournal, $transaction]
'piggybanks.createRelatedTransfer', [$piggyBank, $transactionJournal, $transaction]
);
break;
}
}
if ($connected === false) {
\Session::flash(
'warning', 'Piggy bank "' . e($piggyBank->name)
. '" is not set to draw money from any of the accounts in this transfer'
'warning', 'Piggy bank "' . e($piggyBank->name)
. '" is not set to draw money from any of the accounts in this transfer'
);
}
}
@@ -375,18 +391,21 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
{
/** @var \Firefly\Storage\Category\CategoryRepositoryInterface $catRepository */
$catRepository = \App::make('Firefly\Storage\Category\CategoryRepositoryInterface');
$catRepository->overruleUser($this->_user);
/** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */
$budRepository = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
$budRepository->overruleUser($this->_user);
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */
$accountRepository = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$accountRepository->overruleUser($this->_user);
// update basics first:
$journal->description = $data['description'];
$journal->date = $data['date'];
$amount = floatval($data['amount']);
$journal->date = $data['date'];
$amount = floatval($data['amount']);
// remove previous category, if any:
if (!is_null($journal->categories()->first())) {
@@ -424,7 +443,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
switch ($journal->transactiontype->type) {
case 'Withdrawal':
// means transaction[0] is the users account.
$account = $accountRepository->find($data['account_id']);
$account = $accountRepository->find($data['account_id']);
$beneficiary = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
$transactions[0]->account()->associate($account);
$transactions[1]->account()->associate($beneficiary);
@@ -438,7 +457,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
break;
case 'Deposit':
// means transaction[0] is the beneficiary.
$account = $accountRepository->find($data['account_id']);
$account = $accountRepository->find($data['account_id']);
$beneficiary = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
$journal->transactions[0]->account()->associate($beneficiary);
$journal->transactions[1]->account()->associate($account);
@@ -455,6 +474,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
// attach the new piggy bank, if valid:
/** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */
$piggyRepository = \App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
$piggyRepository->overruleUser($this->_user);
if (isset($data['piggybank_id'])) {
/** @var \Piggybank $piggyBank */
@@ -476,8 +496,8 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
}
if ($connected === false) {
\Session::flash(
'warning', 'Piggy bank "' . e($piggyBank->name)
. '" is not set to draw money from any of the accounts in this transfer'
'warning', 'Piggy bank "' . e($piggyBank->name)
. '" is not set to draw money from any of the accounts in this transfer'
);
}
}

View File

@@ -16,7 +16,7 @@ interface TransactionJournalRepositoryInterface
* @param \Account $toAccount
* @param $description
* @param $amount
* @param Carbon $date
* @param Carbon $date
*
* @return mixed
*/
@@ -27,6 +27,12 @@ interface TransactionJournalRepositoryInterface
*/
public function get();
/**
* @param \User $user
* @return mixed
*/
public function overruleUser(\User $user);
/**
* @param $what
* @param $data
@@ -52,9 +58,9 @@ interface TransactionJournalRepositoryInterface
/**
* @param \Account $account
* @param int $count
* @param Carbon $start
* @param Carbon $end
* @param int $count
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
@@ -62,7 +68,7 @@ interface TransactionJournalRepositoryInterface
/**
* @param \Account $account
* @param Carbon $date
* @param Carbon $date
*
* @return mixed
*/

View File

@@ -60,10 +60,10 @@ class EloquentUserRepository implements UserRepositoryInterface
*/
public function register($array)
{
$user = new \User;
$user->email = isset($array['email']) ? $array['email'] : null;
$user = new \User;
$user->email = isset($array['email']) ? $array['email'] : null;
$user->migrated = 0;
$user->reset = \Str::random(32);
$user->reset = \Str::random(32);
$user->password = \Hash::make(\Str::random(12));
if (!$user->save()) {

View File

@@ -0,0 +1,96 @@
<?php
namespace Firefly\Trigger\Journals;
use Carbon\Carbon;
use Illuminate\Events\Dispatcher;
/**
* Class EloquentJournalTrigger
*
* @package Firefly\Trigger\Journals
*/
class EloquentJournalTrigger
{
/**
* @param \TransactionJournal $journal
*
* @return bool
*/
public function store(\TransactionJournal $journal)
{
// select all reminders for recurring transactions:
if ($journal->transaction_type->type == 'Withdrawal') {
\Log::debug('Trigger on the creation of a withdrawal');
$transaction = $journal->transactions()->orderBy('amount', 'DESC')->first();
$amount = floatval($transaction->amount);
$description = strtolower($journal->description);
$beneficiary = strtolower($transaction->account->name);
// make an array of parts:
$parts = explode(' ', $description);
$parts[] = $beneficiary;
$today = new Carbon;
$set = \RecurringTransactionReminder::
leftJoin(
'recurring_transactions', 'recurring_transactions.id', '=', 'reminders.recurring_transaction_id'
)
->where('startdate', '<', $today->format('Y-m-d'))
->where('enddate', '>', $today->format('Y-m-d'))
->where('amount_min', '<=', $amount)
->where('amount_max', '>=', $amount)->get(['reminders.*']);
/** @var \RecurringTransctionReminder $reminder */
\Log::debug('Have these parts to search for: ' . join('/',$parts));
\Log::debug('Found ' . count($set).' possible matching recurring transactions');
foreach ($set as $index => $reminder) {
/** @var \RecurringTransaction $RT */
$RT = $reminder->recurring_transaction;
$matches = explode(' ', strtolower($RT->match));
\Log::debug($index.': ' . join('/',$matches));
$matchCount = 0;
foreach ($parts as $part) {
if (in_array($part, $matches)) {
$matchCount++;
}
}
if ($matchCount >= count($matches)) {
// we have a match!
\Log::debug(
'Match between new journal "' . join('/', $parts) . '" and RT ' . join('/', $matches) . '.'
);
$journal->recurringTransaction()->associate($RT);
$journal->save();
// also update the reminder.
$reminder->active = 0;
$reminder->save();
return true;
}
}
}
return true;
}
/**
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{
$events->listen('journals.store', 'Firefly\Trigger\Journals\EloquentJournalTrigger@store');
$events->listen('journals.update', 'Firefly\Trigger\Journals\EloquentJournalTrigger@update');
}
/**
* @param \TransactionJournal $journal
*
* @return bool
*/
public function update(\TransactionJournal $journal)
{
return true;
}
}

View File

@@ -1,5 +1,7 @@
<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
/**
* AccountType
*

View File

@@ -33,7 +33,7 @@ class Budget extends Component
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany|\TransactionJournal
*/
public function transactionjournals()
{

View File

@@ -27,7 +27,7 @@ class Component extends SingleTableInheritanceEntity
public static $rules
= [
'user_id' => 'exists:users,id|required',
'name' => 'required|between:1,255',
'name' => ['required', 'between:1,100', 'alphabasic'],
'class' => 'required',
];
protected $table = 'components';

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
/**
* Importentry
*
* @property-read \Importmap $importmap
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $class
* @property integer $importmap_id
* @property integer $old
* @property integer $new
* @method static \Illuminate\Database\Query\Builder|\Importentry whereId($value)
* @method static \Illuminate\Database\Query\Builder|\Importentry whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\Importentry whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\Importentry whereClass($value)
* @method static \Illuminate\Database\Query\Builder|\Importentry whereImportmapId($value)
* @method static \Illuminate\Database\Query\Builder|\Importentry whereOld($value)
* @method static \Illuminate\Database\Query\Builder|\Importentry whereNew($value)
*/
class Importentry extends Eloquent {
public function importmap()
{
return $this->belongsTo('Importmap');
}
}

29
app/models/Importmap.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
/**
* Class Importmap
*
* @property-read \User $user
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $user_id
* @property string $file
* @method static \Illuminate\Database\Query\Builder|\Importmap whereId($value)
* @method static \Illuminate\Database\Query\Builder|\Importmap whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\Importmap whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\Importmap whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\Importmap whereFile($value)
*/
class Importmap extends Eloquent
{
/**
* User
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('User');
}
}

View File

@@ -1,5 +1,5 @@
<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
/**
* TransactionCurrency
*

View File

@@ -47,6 +47,54 @@ use LaravelBook\Ardent\Builder;
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories
*/
class TransactionJournal extends Ardent
{
@@ -89,6 +137,14 @@ class TransactionJournal extends Ardent
return $this->belongsToMany('Component');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function recurringTransaction()
{
return $this->belongsTo('RecurringTransaction');
}
/**
* @return array
*/
@@ -189,7 +245,7 @@ class TransactionJournal extends Ardent
$q->orderBy('amount', 'ASC');
}, 'transactiontype', 'components' => function ($q) {
$q->orderBy('class');
}, 'transactions.account.accounttype']
}, 'transactions.account.accounttype','recurringTransaction']
);
}

View File

@@ -134,7 +134,7 @@ Route::group(['before' => 'auth'], function () {
Route::get('/budgets',['uses' => 'BudgetController@indexByDate','as' => 'budgets.index']);
Route::get('/budgets/create',['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
Route::get('/budgets/budget',['uses' => 'BudgetController@indexByBudget','as' => 'budgets.index.budget']);
Route::get('/budgets/show/{budget}',['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
Route::get('/budgets/show/{budget}/{limitrepetition?}',['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
Route::get('/budgets/edit/{budget}',['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']);
Route::get('/budgets/delete/{budget}',['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']);
@@ -157,8 +157,6 @@ Route::group(['before' => 'auth'], function () {
Route::get('chart/budget/{budget}/session', ['uses' => 'ChartController@budgetSession', 'as' => 'chart.budget.session']);
Route::get('chart/budget/envelope/{limitrepetition}', ['uses' => 'ChartController@budgetLimit', 'as' => 'chart.budget.limit']);
// home controller
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']);
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
@@ -172,20 +170,19 @@ Route::group(['before' => 'auth'], function () {
Route::get('/budgets/limits/delete/{limit}',['uses' => 'LimitController@delete','as' => 'budgets.limits.delete']);
Route::get('/budgets/limits/edit/{limit}',['uses' => 'LimitController@edit','as' => 'budgets.limits.edit']);
Route::get('/migrate',['uses' => 'MigrateController@index', 'as' => 'migrate.index']);
// piggy bank controller
Route::get('/piggybanks',['uses' => 'PiggybankController@index','as' => 'piggybanks.index']);
Route::get('/piggybanks/create/piggybank', ['uses' => 'PiggybankController@createPiggybank','as' => 'piggybanks.create.piggybank']);
Route::get('/piggybanks/create/repeated', ['uses' => 'PiggybankController@createRepeated','as' => 'piggybanks.create.repeated']);
Route::get('/piggybanks/addMoney/{piggybank}', ['uses' => 'PiggybankController@addMoney','as' => 'piggybanks.amount.add']);
Route::get('/piggybanks/removeMoney/{piggybank}', ['uses' => 'PiggybankController@removeMoney','as' => 'piggybanks.amount.remove']);
Route::get('/piggybanks/show/{piggybank}', ['uses' => 'PiggybankController@show','as' => 'piggybanks.show']);
Route::get('/piggybanks/edit/{piggybank}', ['uses' => 'PiggybankController@edit','as' => 'piggybanks.edit']);
Route::get('/piggybanks/delete/{piggybank}', ['uses' => 'PiggybankController@delete','as' => 'piggybanks.delete']);
Route::post('/piggybanks/updateAmount/{piggybank}',['uses' => 'PiggybankController@updateAmount','as' => 'piggybanks.updateAmount']);
// preferences controller
Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']);
@@ -247,6 +244,8 @@ Route::group(['before' => 'csrf|auth'], function () {
Route::post('/budgets/limits/destroy/{limit}',['uses' => 'LimitController@destroy','as' => 'budgets.limits.destroy']);
Route::post('/budgets/limits/update/{limit}',['uses' => 'LimitController@update','as' => 'budgets.limits.update']);
Route::post('/migrate/upload',['uses' => 'MigrateController@upload', 'as' => 'migrate.upload']);
// piggy bank controller
Route::post('/piggybanks/store/piggybank',['uses' => 'PiggybankController@storePiggybank','as' => 'piggybanks.store.piggybank']);

View File

@@ -1,373 +0,0 @@
<?php
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class AccountTest
*
* Test EVERYTHING related to accounts. Models, views controllers.
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @coversDefaultClass \AccountController
*/
class AccountTest extends TestCase
{
protected $_repository;
protected $_user;
protected $_accounts;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_repository = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_accounts = $this->mock('Firefly\Helper\Controllers\AccountInterface');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
Mockery::close();
}
public function testAccountModel()
{
// create account and user:
$account = f::create('Account');
$user = f::create('User');
$user->accounts()->save($account);
// new account? balance should be 0.00
$this->assertEquals(0.0, $account->balance());
// create and link two transactions / piggybanks:
for ($i = 0; $i < 2; $i++) {
$transaction = f::create('Transaction');
$transaction->account()->associate($account);
$transaction->save();
$piggy = f::create('Piggybank');
$piggy->account()->associate($account);
$piggy->save();
}
// test related models
$this->assertCount(2, $account->transactions()->get());
$this->assertCount(2, $account->piggybanks()->get());
// predict should always be null:
$this->assertNull($account->predict(new Carbon));
// user should equal test user:
$this->assertEquals($user->id, $account->user()->first()->id);
$this->assertEquals('testing',\App::environment());
\Log::debug('Hello from test!');
\Log::debug('Number of accounts: ' . \Account::count());
\Log::debug('Number of account types: ' . \AccountType::count());
foreach(\AccountType::get() as $t) {
\Log::debug('AccountType: #'.$t->id.', ' . $t->type);
}
// whatever the account type of this account, searching for it using the
// scope method should return one account:
$accountType = $account->accounttype()->first();
$accounts = $accountType->accounts()->count();
$this->assertCount($accounts, \Account::AccountTypeIn([$accountType->type])->get());
}
/**
* @covers ::create
*/
public function testCreate()
{
// test the view:
View::shouldReceive('make')->once()->with('accounts.create')->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Create account');
// call and final test:
$this->action('GET', 'AccountController@create');
$this->assertResponseOk();
}
/**
* @covers ::delete
*/
public function testDelete()
{
// some prep work.
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to delete:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test the view:
View::shouldReceive('make')->once()->with('accounts.delete')->andReturn(m::self())
->shouldReceive('with')->once()->with('account', m::any())->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Delete account "' . $account->name . '"');
// call and final test:
$this->action('GET', 'AccountController@delete', $account->id);
$this->assertResponseOk();
}
/**
* @covers ::destroy
*/
public function testDestroy()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to destroy:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test if the repository receives an argument:
$this->_repository->shouldReceive('destroy')->once();
// post it:
$this->action('POST', 'AccountController@destroy', $account->id);
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
/**
* @covers ::edit
*/
public function testEdit()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to edit:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test if the repository works:
$this->_accounts->shouldReceive('openingBalanceTransaction')->once()->with(m::any())->andReturn(null);
// test if the view works:
View::shouldReceive('make')->once()->with('accounts.edit')->andReturn(m::self())
->shouldReceive('with')->once()->with('account', m::any())->andReturn(m::self())
->shouldReceive('with')->once()->with('openingBalance', null)->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Edit account "' . $account->name . '"');
$this->action('GET', 'AccountController@edit', $account->id);
$this->assertResponseOk();
}
/**
* @covers ::index
*/
public function testIndex()
{
// two account types:
$personalType = \AccountType::whereType('Default account')->first();
$benType = \AccountType::whereType('Beneficiary account')->first();
// create two accounts:
/** @var \Account $account */
$personal = f::create('Account');
$personal->accountType()->associate($personalType);
$personal->save();
$ben = f::create('Account');
$ben->accountType()->associate($benType);
$ben->save();
/** @var \AccountType $accountType */
$collection = new Collection();
$collection->add($personal);
$collection->add($ben);
$list = [
'personal' => [$personal],
'beneficiaries' => [$ben],
];
// test repository:
$this->_repository->shouldReceive('get')->once()->andReturn($collection);
// test view:
View::shouldReceive('make')->once()->with('accounts.index')->andReturn(m::self())
->shouldReceive('with')->once()->with('accounts', $list)->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'All your accounts');
$this->action('GET', 'AccountController@index');
$this->assertResponseOk();
}
/**
* @covers ::show
*/
public function testShow()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to show:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test view:
View::shouldReceive('make')->once()->with('accounts.show')->andReturn(m::self())
->shouldReceive('with')->once()->with('account', m::any())->andReturn(m::self())
->shouldReceive('with')->once()->with('show', [])->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Details for account "' . $account->name . '"');
$this->_accounts->shouldReceive('show')->once()->andReturn([]);
$this->action('GET', 'AccountController@show', $account->id);
$this->assertResponseOk();
}
/**
* @covers ::store
*/
public function testStore()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store');
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
/**
* @covers ::store
*/
public function testStoreFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
unset($account->name);
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store');
$this->assertRedirectedToRoute('accounts.create');
$this->assertSessionHas('error');
}
public function testStoreRecreate()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store', ['create' => '1']);
$this->assertRedirectedToRoute('accounts.create');
$this->assertSessionHas('success');
}
public function testUpdate()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to update:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
public function testUpdateFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
unset($account->name);
// for successful binding with the account to show:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertRedirectedToRoute('accounts.edit', $account->id);
$this->assertSessionHas('error');
}
}

View File

@@ -1,274 +0,0 @@
<?php
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class BudgetControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class BudgetControllerTest extends TestCase
{
protected $_repository;
protected $_user;
protected $_budgets;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_repository = $this->mock('Firefly\Storage\Budget\BudgetRepositoryInterface');
$this->_budgets = $this->mock('Firefly\Helper\Controllers\BudgetInterface');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
Mockery::close();
}
public function testCreate()
{
$this->action('GET', 'BudgetController@create');
$this->assertResponseOk();
}
public function testDelete()
{
$budget = f::create('Budget');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'BudgetController@delete', $budget->id);
$this->assertResponseOk();
}
public function testDestroy()
{
$budget = f::create('Budget');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
Event::shouldReceive('fire')->once()->with('budgets.destroy', [$budget]);
$this->_repository->shouldReceive('destroy')->once()->andReturn(true);
$this->action('POST', 'BudgetController@destroy', $budget->id);
$this->assertRedirectedToRoute('budgets.index.budget');
$this->assertSessionHas('success');
}
public function testDestroyByDate()
{
$budget = f::create('Budget');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
Event::shouldReceive('fire')->once()->with('budgets.destroy', [$budget]);
$this->_repository->shouldReceive('destroy')->once()->andReturn(true);
$this->action('POST', 'BudgetController@destroy', [$budget->id, 'from' => 'date']);
$this->assertRedirectedToRoute('budgets.index');
$this->assertSessionHas('success');
}
public function testDestroyFails()
{
$budget = f::create('Budget');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
Event::shouldReceive('fire')->once()->with('budgets.destroy', [$budget]);
$this->_repository->shouldReceive('destroy')->once()->andReturn(false);
$this->action('POST', 'BudgetController@destroy', $budget->id);
$this->assertRedirectedToRoute('budgets.index');
$this->assertSessionHas('error');
}
public function testEdit()
{
$budget = f::create('Budget');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'BudgetController@edit', $budget->id);
$this->assertResponseOk();
}
public function testIndexByBudget()
{
$this->_repository->shouldReceive('get')->once()->andReturn([]);
$this->action('GET', 'BudgetController@indexByBudget');
$this->assertResponseOk();
}
public function testIndexByDate()
{
$collection = new Collection();
$this->_repository->shouldReceive('get')->once()->andReturn($collection);
$this->_budgets->shouldReceive('organizeByDate')->with($collection)->andReturn([]);
$this->action('GET', 'BudgetController@indexByDate');
$this->assertResponseOk();
}
public function testShow()
{
$budget = f::create('Budget');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn($budget->email);
$this->session(['start' => new Carbon, 'end' => new Carbon]);
$this->_budgets->shouldReceive('organizeRepetitions')->once()->andReturn([]);
$this->action('GET', 'BudgetController@show', $budget->id);
$this->assertResponseOk();
}
public function testShowNoEnvelope()
{
$budget = f::create('Budget');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn($budget->email);
$this->session(['start' => new Carbon, 'end' => new Carbon]);
$this->_budgets->shouldReceive('outsideRepetitions')->once()->andReturn([]);
$this->action('GET', 'BudgetController@show', [$budget->id, 'noenvelope' => 'true']);
$this->assertResponseOk();
}
public function testShowWithRep()
{
$budget = f::create('Budget');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn($budget->email);
$this->session(['start' => new Carbon, 'end' => new Carbon]);
// $this->_budgets->shouldReceive('show')->once()->andReturn([]);
$arr = [0 => ['limitrepetition' => null, 'limit' => null, 'date' => '']];
$this->_budgets->shouldReceive('organizeRepetition')->once()->andReturn($arr);
$this->action('GET', 'BudgetController@show', [$budget->id, 'rep' => '1']);
$this->assertResponseOk();
}
public function testStore()
{
$budget = f::create('Budget');
$this->_repository->shouldReceive('store')->andReturn($budget);
$this->action('POST', 'BudgetController@store');
$this->assertRedirectedToRoute('budgets.index.budget');
}
public function testStoreFromDate()
{
$budget = f::create('Budget');
$this->_repository->shouldReceive('store')->andReturn($budget);
$this->action('POST', 'BudgetController@store', ['from' => 'date']);
$this->assertRedirectedToRoute('budgets.index');
}
public function testStoreFails()
{
$budget = f::create('Budget');
unset($budget->name);
$this->_repository->shouldReceive('store')->andReturn($budget);
$this->action('POST', 'BudgetController@store', ['from' => 'budget']);
$this->assertRedirectedToRoute('budgets.create');
}
public function testStoreRecreate()
{
$budget = f::create('Budget');
$this->_repository->shouldReceive('store')->andReturn($budget);
$this->action('POST', 'BudgetController@store', ['from' => 'budget', 'create' => '1']);
$this->assertRedirectedToRoute('budgets.create', ['from' => 'budget']);
}
public function testUpdate()
{
$budget = f::create('Budget');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_repository->shouldReceive('update')->andReturn($budget);
Event::shouldReceive('fire')->with('budgets.update', [$budget]);
$this->action('POST', 'BudgetController@update', $budget->id);
$this->assertRedirectedToRoute('budgets.index.budget');
}
public function testUpdateFromDate()
{
$budget = f::create('Budget');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_repository->shouldReceive('update')->andReturn($budget);
Event::shouldReceive('fire')->with('budgets.update', [$budget]);
//$this->_user->shouldReceive('budgets')->andReturn([]); // trigger
$this->action('POST', 'BudgetController@update', [$budget->id, 'from' => 'date']);
$this->assertRedirectedToRoute('budgets.index');
}
public function testUpdateFails()
{
$budget = f::create('Budget');
unset($budget->name);
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($budget->user_id);
$this->_repository->shouldReceive('update')->andReturn($budget);
$this->action('POST', 'BudgetController@update', $budget->id);
$this->assertRedirectedToRoute('budgets.edit', $budget->id);
}
}

View File

@@ -1,183 +0,0 @@
<?php
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class CategoryControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class CategoryControllerTest extends TestCase
{
protected $_repository;
protected $_user;
protected $_category;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_repository = $this->mock('Firefly\Storage\Category\CategoryRepositoryInterface');
$this->_category = $this->mock('Firefly\Helper\Controllers\CategoryInterface');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
Mockery::close();
}
public function testCreate()
{
$this->action('GET', 'CategoryController@create');
$this->assertResponseOk();
}
public function testDelete()
{
$category = f::create('Category');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'CategoryController@delete', $category->id);
$this->assertResponseOk();
}
public function testDestroy()
{
$category = f::create('Category');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_repository->shouldReceive('destroy')->once()->andReturn(true);
$this->action('POST', 'CategoryController@destroy', $category->id);
$this->assertRedirectedToRoute('categories.index');
$this->assertSessionHas('success');
}
public function testDestroyFails()
{
$category = f::create('Category');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_repository->shouldReceive('destroy')->once()->andReturn(false);
$this->action('POST', 'CategoryController@destroy', $category->id);
$this->assertRedirectedToRoute('categories.index');
$this->assertSessionHas('error');
}
public function testEdit()
{
$category = f::create('Category');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'CategoryController@edit', $category->id);
$this->assertResponseOk();
}
public function testIndex()
{
$category = f::create('Category');
$collection = new Collection();
$collection->add($category);
$this->_repository->shouldReceive('get')->with()->once()->andReturn($collection);
$this->action('GET', 'CategoryController@index');
$this->assertResponseOk();
}
public function testShow()
{
$category = f::create('Category');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn($category->email);
$this->session(['start' => new Carbon, 'end' => new Carbon]);
$this->_category->shouldReceive('journalsInRange')->once()->andReturn([]);
$this->action('GET', 'CategoryController@show', $category->id);
$this->assertResponseOk();
}
public function testStore()
{
$category = f::create('Category');
$this->_repository->shouldReceive('store')->andReturn($category);
$this->action('POST', 'CategoryController@store');
$this->assertRedirectedToRoute('categories.index');
}
public function testStoreFails()
{
$category = f::create('Category');
unset($category->name);
$this->_repository->shouldReceive('store')->andReturn($category);
$this->action('POST', 'CategoryController@store');
$this->assertRedirectedToRoute('categories.create');
}
public function testStoreRecreate()
{
$category = f::create('Category');
$this->_repository->shouldReceive('store')->andReturn($category);
$this->action('POST', 'CategoryController@store', ['create' => '1']);
$this->assertRedirectedToRoute('categories.create');
}
public function testUpdate()
{
$category = f::create('Category');
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_repository->shouldReceive('update')->andReturn($category);
$this->action('POST', 'CategoryController@update', $category->id);
$this->assertRedirectedToRoute('categories.index');
}
public function testUpdateFails()
{
$category = f::create('Category');
unset($category->name);
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_repository->shouldReceive('update')->andReturn($category);
$this->action('POST', 'CategoryController@update', [$category->id]);
$this->assertResponseStatus(302);
}
}

View File

@@ -1,138 +0,0 @@
<?php
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class ChartControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class ChartControllerTest extends TestCase
{
protected $_user;
// protected $_repository;
protected $_accounts;
protected $_charts;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_charts = $this->mock('Firefly\Helper\Controllers\ChartInterface');
// $this->_category = $this->mock('Firefly\Helper\Controllers\CategoryInterface');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
Mockery::close();
}
public function testCategoryShowChart()
{
$this->session(['start' => new Carbon, 'end' => new Carbon, 'range' => '1M']);
$category = f::create('Category');
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($category->user_id);
$this->_charts->shouldReceive('categoryShowChart')->once()->andReturn([]);
$this->action('GET', 'ChartController@categoryShowChart', $category->id);
$this->assertResponseOk();
}
public function testHomeAccount()
{
$account = f::create('Account');
$collection = new Collection();
$collection->add($account);
$this->session(['start' => new Carbon, 'end' => new Carbon, 'range' => '1M']);
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('bla@bla');
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn(1);
$this->_accounts->shouldReceive('getByIds')->andReturn($collection);
$this->_charts->shouldReceive('account')->once()->andReturn([]);
$this->action('GET', 'ChartController@homeAccount');
$this->assertResponseOk();
}
public function testHomeAccountInfo()
{
$account = f::create('Account');
$accountType = \AccountType::whereType('Default account')->first();
$account->accounttype()->associate($accountType);
$account->save();
// for successful binding:
Auth::shouldReceive('user')->andReturn($account->user()->first());
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('bla@bla');
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($account->user_id);
$this->_accounts->shouldReceive('findByName')->andReturn($account);
$this->_charts->shouldReceive('accountDailySummary')->once()->andReturn(['rows' => [], 'sum' => 0]);
$this->call('GET', 'chart/home/info/' . $account->name . '/01/08/2014');
$this->assertResponseOk();
}
public function testHomeAccountWithAccount()
{
$account = f::create('Account');
$this->session(['start' => new Carbon, 'end' => new Carbon, 'range' => '1M']);
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('bla@bla');
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($account->user_id);
$this->_charts->shouldReceive('account')->once()->andReturn([]);
$this->action('GET', 'ChartController@homeAccount', $account->id);
$this->assertResponseOk();
}
public function testHomeBudgets()
{
$date = new Carbon;
$this->session(['start' => $date]);
$this->_charts->shouldReceive('budgets')->once()->with($date)->andReturn([]);
$this->action('GET', 'ChartController@homeBudgets');
$this->assertResponseOk();
}
public function testHomeCategories()
{
$start = new Carbon;
$end = new Carbon;
$this->_charts->shouldReceive('categories')->once()->with($start, $end)->andReturn([]);
$this->session(['start' => $start, 'end' => $end]);
$this->action('GET', 'ChartController@homeCategories');
$this->assertResponseOk();
}
}

View File

@@ -1,142 +0,0 @@
<?php
use Carbon\Carbon as Carbon;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class HomeControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class HomeControllerTest extends TestCase
{
protected $_accounts;
protected $_repository;
protected $_preferences;
protected $_journals;
protected $_reminders;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_accounts = $this->mock('Firefly\Helper\Controllers\AccountInterface');
$this->_repository = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_preferences = $this->mock('Firefly\Helper\Preferences\PreferencesHelperInterface');
$this->_journals = $this->mock('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
$this->_reminders = $this->mock('Firefly\Storage\Reminder\ReminderRepositoryInterface');
}
public function tearDown()
{
Mockery::close();
}
public function testFlush()
{
$this->action('GET', 'HomeController@flush');
$this->assertRedirectedToRoute('index');
}
public function testIndex()
{
// mock preference:
$preference = $this->mock('Preference');
$preference->shouldReceive('getAttribute')->with('data')->andReturn([]);
Event::shouldReceive('fire')->with('limits.check');
Event::shouldReceive('fire')->with('piggybanks.check');
Event::shouldReceive('fire')->with('recurring.check');
$this->_reminders->shouldReceive('getCurrentRecurringReminders')->once()->andReturn([]);
// mock accounts:
$this->_repository->shouldReceive('count')->once()->andReturn(0);
$this->_repository->shouldReceive('getActiveDefault')->once()->andReturn([]);
// mock preferences:
$this->_preferences->shouldReceive('get')->with('frontpageAccounts', [])->andReturn($preference);
$this->action('GET', 'HomeController@index');
$this->assertResponseOk();
}
public function testIndexWithAccount()
{
$account = f::create('Account');
$start = new Carbon;
$end = new Carbon;
$this->session(['start' => $start, 'end' => $end]);
// mock preference:
$preference = $this->mock('Preference');
$preference->shouldReceive('getAttribute')->with('data')->andReturn([$account->id]);
Event::shouldReceive('fire')->with('limits.check');
Event::shouldReceive('fire')->with('piggybanks.check');
Event::shouldReceive('fire')->with('recurring.check');
$this->_reminders->shouldReceive('getCurrentRecurringReminders')->once()->andReturn([]);
// mock accounts:
$this->_repository->shouldReceive('count')->once()->andReturn(0);
$this->_repository->shouldReceive('getByIds')->with([$account->id])->once()->andReturn([$account]);
// mock preferences:
$this->_preferences->shouldReceive('get')->with('frontpageAccounts', [])->andReturn($preference);
// mock journals:
$this->_journals->shouldReceive('getByAccountInDateRange')->once()->with($account, 10, $start, $end)->andReturn(
[1, 2]
);
$this->action('GET', 'HomeController@index');
$this->assertResponseOk();
}
public function testIndexWithAccounts()
{
$accountOne = f::create('Account');
$accountTwo = f::create('Account');
$accounThree = f::create('Account');
$set = [$accountOne, $accountTwo, $accounThree];
$ids = [$accountOne->id, $accountTwo->id, $accounThree->id];
$start = new Carbon;
$end = new Carbon;
$this->session(['start' => $start, 'end' => $end]);
// mock preference:
$preference = $this->mock('Preference');
$preference->shouldReceive('getAttribute')->with('data')->andReturn($ids);
Event::shouldReceive('fire')->with('limits.check');
Event::shouldReceive('fire')->with('piggybanks.check');
Event::shouldReceive('fire')->with('recurring.check');
$this->_reminders->shouldReceive('getCurrentRecurringReminders')->once()->andReturn([]);
// mock accounts:
$this->_repository->shouldReceive('count')->once()->andReturn(0);
$this->_repository->shouldReceive('getByIds')->with($ids)->once()->andReturn(
$set
);
// mock preferences:
$this->_preferences->shouldReceive('get')->with('frontpageAccounts', [])->andReturn($preference);
// mock journals:
$this->_journals->shouldReceive('getByAccountInDateRange')->andReturn([1, 2]);
$this->action('GET', 'HomeController@index');
$this->assertResponseOk();
}
}

View File

@@ -1,45 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
/**
* Class JsonControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class JsonControllerTest extends TestCase
{
protected $_accounts;
protected $_categories;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_categories = $this->mock('Firefly\Storage\Category\CategoryRepositoryInterface');
}
public function tearDown()
{
Mockery::close();
}
public function testBeneficiaries()
{
$beneficiary = f::create('Account');
$this->_accounts->shouldReceive('getBeneficiaries')->once()->andReturn([$beneficiary]);
$this->action('GET', 'JsonController@beneficiaries');
$this->assertResponseOk();
}
public function testCategories()
{
$category = f::create('Category');
$this->_categories->shouldReceive('get')->once()->andReturn([$category]);
$this->action('GET', 'JsonController@categories');
$this->assertResponseOk();
}
}

View File

@@ -1,245 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class LimitControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class LimitControllerTest extends TestCase
{
protected $_budgets;
protected $_limits;
protected $_user;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
$this->_budgets = $this->mock('Firefly\Storage\Budget\BudgetRepositoryInterface');
$this->_limits = $this->mock('Firefly\Storage\Limit\LimitRepositoryInterface');
}
public function tearDown()
{
Mockery::close();
}
public function testCreate()
{
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
$this->action('GET', 'LimitController@create');
$this->assertResponseOk();
}
public function testDelete()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'LimitController@delete', $limit->id);
$this->assertResponseOk();
}
public function testDestroy()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_limits->shouldReceive('destroy')->once()->andReturn(true);
$this->action('POST', 'LimitController@destroy', $limit->id);
$this->assertResponseStatus(302);
}
public function testDestroyFails()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_limits->shouldReceive('destroy')->once()->andReturn(false);
$this->action('POST', 'LimitController@destroy', $limit->id);
$this->assertResponseStatus(302);
}
public function testDestroyRedirect()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_limits->shouldReceive('destroy')->once()->andReturn(true);
$this->action('POST', 'LimitController@destroy', [$limit->id, 'from' => 'date']);
$this->assertResponseStatus(302);
}
public function testEdit()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'LimitController@edit', $limit->id);
$this->assertResponseOk();
}
public function testStore()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
$this->_limits->shouldReceive('store')->once()->andReturn($limit);
$this->action('POST', 'LimitController@store');
$this->assertRedirectedToRoute('budgets.index.budget');
$this->assertResponseStatus(302);
}
public function testStoreFails()
{
$budget = f::create('Budget');
$limit = f::create('Limit');
$limit->budget()->associate($budget);
$limit->save();
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
unset($limit->startdate);
unset($limit->component_id);
$this->_limits->shouldReceive('store')->once()->andReturn($limit);
$this->action('POST', 'LimitController@store', $budget->id);
$this->assertResponseStatus(302);
}
public function testStoreRedirect()
{
$budget = f::create('Budget');
$limit = f::create('Limit');
$limit->budget()->associate($budget);
$limit->save();
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
$this->_limits->shouldReceive('store')->once()->andReturn($limit);
$this->action('POST', 'LimitController@store', [$budget->id, 'from' => 'date']);
$this->assertResponseStatus(302);
}
public function testUpdate()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_limits->shouldReceive('update')->once()->andReturn($limit);
$this->action(
'POST', 'LimitController@update',
[$limit->id,
'date' => '02-02-2012',
'period' => 'monthly',
'repeats' => 0,
'amount' => '0.01'
]
);
$this->assertResponseStatus(302);
}
public function testUpdateFails()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
unset($limit->amount);
$this->_limits->shouldReceive('update')->once()->andReturn($limit);
$this->action(
'POST', 'LimitController@update',
$limit->id
);
$this->assertResponseStatus(302);
}
public function testUpdateRedirect()
{
$limit = f::create('Limit');
$limitrepetition = f::create('LimitRepetition');
$limit->limitrepetitions()->save($limitrepetition);
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($limit->budget()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_limits->shouldReceive('update')->once()->andReturn($limit);
$this->action(
'POST', 'LimitController@update',
[$limit->id,
'date' => '02-02-2012',
'period' => 'monthly',
'repeats' => 0,
'amount' => '0.01',
'from' => 'date'
]
);
$this->assertResponseStatus(302);
}
}

View File

@@ -1,440 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class PiggybankControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class PiggybankControllerTest extends TestCase
{
protected $_accounts;
protected $_piggybanks;
protected $_user;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
$this->_accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_piggybanks = $this->mock('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
}
public function tearDown()
{
m::close();
}
public function testAddMoneyGET()
{
$piggyBank = f::create('Piggybank');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_piggybanks->shouldReceive('leftOnAccount')->andReturn(1);
$this->action('GET', 'PiggybankController@addMoney', $piggyBank->id);
$this->assertResponseOk();
}
public function testCreatePiggybank()
{
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->once()->andReturn([]);
$this->action('GET', 'PiggybankController@createPiggybank');
$this->assertResponseOk();
}
public function testCreateRepeated()
{
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->once()->andReturn([]);
$this->action('GET', 'PiggybankController@createRepeated');
$this->assertResponseOk();
}
public function testDelete()
{
$piggyBank = f::create('Piggybank');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'PiggybankController@delete', $piggyBank->id);
$this->assertResponseOk();
}
public function testDestroy()
{
$piggyBank = f::create('Piggybank');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_piggybanks->shouldReceive('destroy')->andReturn(true);
Event::shouldReceive('fire')->with('piggybanks.destroy', [$piggyBank]);
$this->action('POST', 'PiggybankController@destroy', $piggyBank->id);
$this->assertResponseStatus(302);
}
public function testEdit()
{
$piggyBank = f::create('Piggybank');
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->once()->andReturn([]);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'PiggybankController@edit', $piggyBank->id);
$this->assertResponseOk();
}
public function testEditRepeated()
{
$piggyBank = f::create('Piggybank');
$piggyBank->repeats = 1;
$piggyBank->save();
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->once()->andReturn([]);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'PiggybankController@edit', $piggyBank->id);
$this->assertResponseOk();
}
public function testIndex()
{
$aOne = f::create('Account');
$aTwo = f::create('Account');
$one = f::create('Piggybank');
$one->account()->associate($aOne);
$two = f::create('Piggybank');
$two->account()->associate($aOne);
$three = f::create('Piggybank');
$three->account()->associate($aTwo);
$this->_piggybanks->shouldReceive('get')->andReturn([$one, $two, $three]);
$this->_piggybanks->shouldReceive('countRepeating')->andReturn(0);
$this->_piggybanks->shouldReceive('leftOnAccount')->andReturn(0);
$this->_piggybanks->shouldReceive('countNonrepeating')->andReturn(0);
Event::shouldReceive('fire')->with('piggybanks.change');
$this->action('GET', 'PiggybankController@index');
$this->assertResponseOk();
}
public function testModifyMoneyAddPOST()
{
$piggyBank = f::create('Piggybank');
$piggyBank->targetamount = 200;
$piggyBank->save();
$input = [
$piggyBank->id,
'amount' => 10.0,
'what' => 'add'
];
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
Event::shouldReceive('fire'); //->with('piggybanks.modifyAmountAdd', [$piggyBank, 10.0]);
$this->_piggybanks->shouldReceive('modifyAmount')->once();
$this->_piggybanks->shouldReceive('leftOnAccount')->once()->andReturn(200);
$this->action('POST', 'PiggybankController@modMoney', $input);
$this->assertSessionHas('success');
$this->assertResponseStatus(302);
}
public function testModifyMoneyAddPOSTFails()
{
$piggyBank = f::create('Piggybank');
$piggyBank->targetamount = 200;
$piggyBank->save();
$input = [
$piggyBank->id,
'amount' => 10.0,
'what' => 'add'
];
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($piggyBank->account()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
Event::shouldReceive('fire')->with('piggybanks.modifyAmountAdd', [$piggyBank, -10.0]);
$this->_piggybanks->shouldReceive('leftOnAccount')->once()->andReturn(5);
$this->action('POST', 'PiggybankController@modMoney', $input);
$this->assertSessionHas('warning');
$this->assertResponseStatus(302);
}
/**
* @expectedException \Firefly\Exception\FireflyException
*/
public function testModifyMoneyPOSTException()
{
$piggyBank = f::create('Piggybank');
$piggyBank->targetamount = 200;
$piggyBank->save();
$input = [
$piggyBank->id,
'amount' => 10.0,
'what' => 'yomoma'
];
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($piggyBank->account()->first()->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('POST', 'PiggybankController@modMoney', $input);
$this->assertSessionHas('warning');
$this->assertResponseStatus(302);
}
public function testModifyMoneyRemovePOST()
{
$pig = $this->mock('Piggybank');
$piggybank = f::create('Piggybank');
$rep = f::create('PiggybankRepetition');
$rep->piggybank_id = $piggybank->id;
$rep->save();
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$rep->piggybank()->first()->account()->first()->user_id
);
$pig->shouldReceive('currentRelevantRep')->andReturn($rep);
$this->_piggybanks->shouldReceive('leftOnAccount')->andReturn(11);
$this->_piggybanks->shouldReceive('modifyAmount')->once();
$input = [
$rep->piggybank()->first()->id,
'amount' => 10.0,
'what' => 'remove'
];
$this->action('POST', 'PiggybankController@modMoney', $input);
$this->assertSessionHas('success');
$this->assertResponseStatus(302);
}
public function testModifyMoneyRemovePOSTFails()
{
$pig = $this->mock('Piggybank');
$piggybank = f::create('Piggybank');
$rep = f::create('PiggybankRepetition');
$rep->piggybank_id = $piggybank->id;
$rep->currentAmount = 5;
$rep->save();
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$rep->piggybank()->first()->account()->first()->user_id
);
$pig->shouldReceive('currentRelevantRep')->andReturn($rep);
$input = [
$rep->piggybank()->first()->id,
'amount' => 10.0,
'what' => 'remove'
];
$this->action('POST', 'PiggybankController@modMoney', $input);
$this->assertSessionHas('warning');
$this->assertResponseStatus(302);
}
public function testRemoveMoneyGET()
{
$pig = $this->mock('Piggybank');
$piggybank = f::create('Piggybank');
$rep = f::create('PiggybankRepetition');
$rep->piggybank_id = $piggybank->id;
$rep->save();
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$rep->piggybank()->first()->account()->first()->user_id
);
$pig->shouldReceive('currentRelevantRep')->andReturn($rep);
$this->_piggybanks->shouldReceive('leftOnAccount')->andReturn(1)->once();
$this->action('GET', 'PiggybankController@removeMoney', $piggybank->id);
$this->assertResponseOk();
}
public function testShow()
{
$pig = $this->mock('Piggybank');
$piggybank = f::create('Piggybank');
$rep = f::create('PiggybankRepetition');
$rep->piggybank_id = $piggybank->id;
$rep->save();
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn(
$piggybank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->andReturn('some@email');
$pig->shouldReceive('currentRelevantRep')->andReturn($rep);
// repos:
$this->_piggybanks->shouldReceive('leftOnAccount');
$this->action('GET', 'PiggybankController@show', $piggybank->id);
$this->assertResponseOk();
}
public function testStoreRepeated()
{
$piggy = f::create('Piggybank');
$piggy->repeats = 1;
$piggy->save();
Event::shouldReceive('fire')->with('piggybanks.store', [$piggy])->once();
$this->_piggybanks->shouldReceive('store')->once()->andReturn($piggy);
$this->action('POST', 'PiggybankController@storeRepeated');
$this->assertResponseStatus(302);
}
public function testStoreRepeatedFails()
{
$piggy = f::create('Piggybank');
unset($piggy->id);
$this->_piggybanks->shouldReceive('store')->once()->andReturn($piggy);
$this->action('POST', 'PiggybankController@storeRepeated');
$this->assertResponseStatus(302);
}
public function testUpdate()
{
$piggyBank = f::create('Piggybank');
$this->_piggybanks->shouldReceive('update')->andReturn($piggyBank);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
Event::shouldReceive('fire')->with('piggybanks.update', [$piggyBank]);
$this->action('POST', 'PiggybankController@update', $piggyBank->id);
$this->assertResponseStatus(302);
}
public function testUpdateFails()
{
$piggyBank = f::create('Piggybank');
unset($piggyBank->name);
$this->_piggybanks->shouldReceive('update')->andReturn($piggyBank);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn(
$piggyBank->account()->first()->user_id
);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
Event::shouldReceive('fire')->with('piggybanks.change');
$this->action('POST', 'PiggybankController@update', $piggyBank->id);
$this->assertResponseStatus(302);
}
public function teststorePiggybank()
{
$piggy = f::create('Piggybank');
$piggy->repeats = 0;
$piggy->save();
Event::shouldReceive('fire')->with('piggybanks.store', [$piggy])->once();
$this->_piggybanks->shouldReceive('store')->once()->andReturn($piggy);
$this->action('POST', 'PiggybankController@storePiggybank');
$this->assertResponseStatus(302);
}
public function teststorePiggybankFails()
{
$piggy = f::create('Piggybank');
unset($piggy->id);
$this->_piggybanks->shouldReceive('store')->once()->andReturn($piggy);
$this->action('POST', 'PiggybankController@storePiggybank');
$this->assertResponseStatus(302);
}
}

View File

@@ -1,56 +0,0 @@
<?php
use Mockery as m;
/**
* Class PreferencesControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class PreferencesControllerTest extends TestCase
{
protected $_user;
protected $_helper;
protected $_accounts;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
$this->_helper = $this->mock('Firefly\Helper\Preferences\PreferencesHelperInterface');
$this->_accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
}
public function tearDown()
{
m::close();
}
public function testIndex()
{
$viewRange = $this->mock('Preference');
$viewRange->shouldReceive('getAttribute')->with('data')->andReturn('1M');
$this->_accounts->shouldReceive('getDefault')->andReturn([]);
$this->_helper->shouldReceive('get')->with('viewRange', '1M')->andReturn($viewRange);
$this->_helper->shouldReceive('get')->with('frontpageAccounts', [])->andReturn([]);
$this->action('GET', 'PreferencesController@index');
$this->assertResponseOk();
}
public function testPostIndex()
{
$this->_helper->shouldReceive('set')->with('frontpageAccounts', [1]);
$this->_helper->shouldReceive('set')->with('viewRange', '1M');
$this->action('POST', 'PreferencesController@postIndex', ['frontpageAccounts' => [1], 'viewRange' => '1M']);
$this->assertResponseStatus(302);
}
}

View File

@@ -1,135 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class ProfileControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class ProfileControllerTest extends TestCase
{
protected $_user;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
m::close();
}
public function testChangePassword()
{
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($this->_user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'ProfileController@changePassword');
$this->assertResponseOk();
}
public function testIndex()
{
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($this->_user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'ProfileController@index');
$this->assertResponseOk();
}
public function testPostChangePasswordDifferentNew()
{
$user = f::create('User');
// for binding
Auth::shouldReceive('user')->andReturn($user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn($user->email);
$this->_user->shouldReceive('getAttribute')->with('password')->andReturn($user->password);
$this->action(
'POST', 'ProfileController@postChangePassword',
['old' => 'sander', 'new1' => 'sander1', 'new2' => 'sander2']
);
$this->assertResponseOk();
}
public function testPostChangePasswordOK()
{
$user = f::create('User');
$user->password = 'sander';
$user->save();
// for binding
Auth::shouldReceive('user')->andReturn($user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn($user->email);
$this->_user->shouldReceive('getAttribute')->with('password')->andReturn($user->password);
$this->action(
'POST', 'ProfileController@postChangePassword',
['old' => 'sander', 'new1' => 'sander2', 'new2' => 'sander2']
);
$this->assertSessionHas('success');
$this->assertResponseStatus(302);
}
public function testPostChangePasswordNoCurrent()
{
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($this->_user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_user->shouldReceive('getAttribute')->with('password')->andReturn('Blablabla');
$this->action('POST', 'ProfileController@postChangePassword', ['old' => '']);
$this->assertResponseOk();
}
public function testPostChangePasswordNoMatchNew()
{
$user = f::create('User');
// for binding
Auth::shouldReceive('user')->andReturn($user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn($user->email);
$this->_user->shouldReceive('getAttribute')->with('password')->andReturn($user->password);
$this->action(
'POST', 'ProfileController@postChangePassword', ['old' => 'sander', 'new1' => 'sander', 'new2' => 'sander']
);
$this->assertResponseOk();
}
public function testPostChangePasswordSame()
{
$user = f::create('User');
// for binding
Auth::shouldReceive('user')->andReturn($user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($user->id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn($user->email);
$this->_user->shouldReceive('getAttribute')->with('password')->andReturn($user->password);
$this->action('POST', 'ProfileController@postChangePassword', ['old' => 'sander']);
$this->assertResponseOk();
}
}

View File

@@ -1,178 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class RecurringControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class RecurringControllerTest extends TestCase
{
protected $_user;
protected $_repository;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
$this->_repository = $this->mock(
'Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface'
);
}
public function tearDown()
{
m::close();
}
public function testCreate()
{
$this->action('GET', 'RecurringController@create');
$this->assertResponseOk();
}
public function testDelete()
{
$recurringTransaction = f::create('RecurringTransaction');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($recurringTransaction->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'RecurringController@delete', $recurringTransaction->id);
$this->assertResponseOk();
}
public function testDestroy()
{
$recurringTransaction = f::create('RecurringTransaction');
Event::shouldReceive('fire')->with('recurring.destroy',m::any());
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($recurringTransaction->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_repository->shouldReceive('destroy')->andReturn(true);
$this->action('POST', 'RecurringController@destroy', $recurringTransaction->id);
$this->assertResponseStatus(302);
}
public function testDestroyFails()
{
$recurringTransaction = f::create('RecurringTransaction');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
Event::shouldReceive('fire')->with('recurring.destroy',m::any());
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($recurringTransaction->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_repository->shouldReceive('destroy')->andReturn(false);
$this->action('POST', 'RecurringController@destroy', $recurringTransaction->id);
$this->assertResponseStatus(302);
}
public function testEdit()
{
$recurringTransaction = f::create('RecurringTransaction');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($recurringTransaction->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn('some@email');
$this->action('GET', 'RecurringController@edit', $recurringTransaction->id);
$this->assertResponseOk();
}
public function testIndex()
{
$this->_repository->shouldReceive('get')->andReturn([]);
$this->action('GET', 'RecurringController@index');
$this->assertResponseOk();
}
public function testShow()
{
$recurringTransaction = f::create('RecurringTransaction');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($recurringTransaction->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'RecurringController@show', $recurringTransaction->id);
$this->assertResponseOk();
}
public function testStore()
{
$recurringTransaction = f::create('RecurringTransaction');
Event::shouldReceive('fire')->with('recurring.store',m::any());
$this->_repository->shouldReceive('store')->andReturn($recurringTransaction);
$this->action('POST', 'RecurringController@store');
$this->assertResponseStatus(302);
}
public function testStoreRedirect()
{
$recurringTransaction = f::create('RecurringTransaction');
Event::shouldReceive('fire')->with('recurring.store',m::any());
$this->_repository->shouldReceive('store')->andReturn($recurringTransaction);
$this->action('POST', 'RecurringController@store', ['create' => '1']);
$this->assertResponseStatus(302);
}
public function testStoreFails()
{
$recurringTransaction = f::create('RecurringTransaction');
unset($recurringTransaction->active);
unset($recurringTransaction->automatch);
$this->_repository->shouldReceive('store')->andReturn($recurringTransaction);
$this->action('POST', 'RecurringController@store', ['create' => '1']);
$this->assertResponseStatus(302);
}
public function testUpdate()
{
$recurringTransaction = f::create('RecurringTransaction');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->andReturn($recurringTransaction->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
Event::shouldReceive('fire')->with('recurring.update',m::any());
$this->_repository->shouldReceive('update')->andReturn($recurringTransaction);
$this->action('POST', 'RecurringController@update', $recurringTransaction->id);
$this->assertResponseStatus(302);
}
}

View File

@@ -1,30 +0,0 @@
<?php
use Mockery as m;
/**
* Class ReportControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class ReportControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
}
public function tearDown()
{
m::close();
}
public function testIndex()
{
$this->action('GET', 'ReportController@index');
$this->assertResponseOk();
}
}

View File

@@ -1,30 +0,0 @@
<?php
use Mockery as m;
/**
* Class SearchControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class SearchControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
}
public function tearDown()
{
m::close();
}
public function testIndex()
{
$this->action('GET', 'SearchController@index');
$this->assertResponseOk();
}
}

View File

@@ -1,312 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class TransactionControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class TransactionControllerTest extends TestCase
{
protected $_user;
protected $_repository;
protected $_accounts;
protected $_budgets;
protected $_piggies;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
$this->_repository = $this->mock('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface');
$this->_accounts = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_budgets = $this->mock('Firefly\Storage\Budget\BudgetRepositoryInterface');
$this->_piggies = $this->mock('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
}
public function tearDown()
{
m::close();
}
public function testCreateDeposit()
{
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->andReturn([]);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
$this->_piggies->shouldReceive('get')->andReturn([]);
$this->action('GET', 'TransactionController@create', ['what' => 'deposit']);
$this->assertResponseOk();
}
public function testCreateTransfer()
{
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->andReturn([]);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
$this->_piggies->shouldReceive('get')->andReturn([]);
$this->action('GET', 'TransactionController@create', ['what' => 'transfer']);
$this->assertResponseOk();
}
public function testCreateWithdrawal()
{
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->andReturn([]);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
$this->_piggies->shouldReceive('get')->andReturn([]);
$this->action('GET', 'TransactionController@create', ['what' => 'withdrawal']);
$this->assertResponseOk();
}
public function testDelete()
{
$journal = f::create('TransactionJournal');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'TransactionController@delete', $journal->id);
$this->assertResponseOk();
}
public function testDestroy()
{
$journal = f::create('TransactionJournal');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('POST', 'TransactionController@destroy', $journal->id);
$this->assertResponseStatus(302);
}
public function testEdit()
{
$journal = f::create('TransactionJournal');
$type = f::create('TransactionType');
$type->type = 'Withdrawal';
$type->save();
$journal->transactiontype()->associate($type);
$journal->save();
$category = f::create('Category');
$journal->categories()->save($category);
$budget = f::create('Budget');
$journal->budgets()->save($budget);
$one = f::create('Transaction');
$two = f::create('Transaction');
$one->transactionjournal()->associate($journal);
$two->transactionjournal()->associate($journal);
$one->save();
$two->save();
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->andReturn([]);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_piggies->shouldReceive('get')->once()->andReturn([]);
$this->action('GET', 'TransactionController@edit', $journal->id);
$this->assertResponseOk();
}
public function testEditDeposit()
{
$journal = f::create('TransactionJournal');
$type = f::create('TransactionType');
$type->type = 'Deposit';
$type->save();
$journal->transactiontype()->associate($type);
$journal->save();
$category = f::create('Category');
$journal->categories()->save($category);
$budget = f::create('Budget');
$journal->budgets()->save($budget);
$one = f::create('Transaction');
$two = f::create('Transaction');
$one->transactionjournal()->associate($journal);
$two->transactionjournal()->associate($journal);
$one->save();
$two->save();
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->andReturn([]);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
$this->_piggies->shouldReceive('get')->once()->andReturn([]);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'TransactionController@edit', $journal->id);
$this->assertResponseOk();
}
public function testEditTransfer()
{
$journal = f::create('TransactionJournal');
$type = f::create('TransactionType');
$type->type = 'Transfer';
$type->save();
$journal->transactiontype()->associate($type);
$journal->save();
$category = f::create('Category');
$journal->categories()->save($category);
$budget = f::create('Budget');
$journal->budgets()->save($budget);
$one = f::create('Transaction');
$two = f::create('Transaction');
$one->transactionjournal()->associate($journal);
$two->transactionjournal()->associate($journal);
$one->save();
$two->save();
$this->_accounts->shouldReceive('getActiveDefaultAsSelectList')->andReturn([]);
$this->_budgets->shouldReceive('getAsSelectList')->andReturn([]);
$this->_piggies->shouldReceive('get')->once()->andReturn([]);
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'TransactionController@edit', $journal->id);
$this->assertResponseOk();
}
public function testIndex()
{
$journal = f::create('TransactionJournal');
$type = f::create('TransactionType');
$type->type = 'Withdrawal';
$type->save();
$journal->transactiontype()->associate($type);
$journal->save();
$one = f::create('Transaction');
$two = f::create('Transaction');
$one->transactionjournal()->associate($journal);
$two->transactionjournal()->associate($journal);
$one->save();
$two->save();
// make a paginator
$paginator = Paginator::make([$journal], 1, 1);
$this->_repository->shouldReceive('paginate')->with(25)->andReturn($paginator);
$this->_repository->shouldReceive('get')->andReturn([]);
$this->action('GET', 'TransactionController@index');
$this->assertResponseOk();
}
public function testShow()
{
$journal = f::create('TransactionJournal');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'TransactionController@show', $journal->id);
$this->assertResponseOk();
}
public function testStore()
{
$journal = f::create('TransactionJournal');
$this->_repository->shouldReceive('store')->andReturn($journal);
$this->action('POST', 'TransactionController@store', ['what' => 'deposit']);
$this->assertResponseStatus(302);
}
public function testStoreFails()
{
$journal = f::create('TransactionJournal');
unset($journal->description);
$this->_repository->shouldReceive('store')->andReturn($journal);
$this->action('POST', 'TransactionController@store', ['what' => 'deposit', 'create' => '1']);
$this->assertResponseStatus(302);
}
public function testStoreRedirect()
{
$journal = f::create('TransactionJournal');
$this->_repository->shouldReceive('store')->andReturn($journal);
$this->action('POST', 'TransactionController@store', ['what' => 'deposit', 'create' => '1']);
$this->assertResponseStatus(302);
}
public function testUpdate()
{
$journal = f::create('TransactionJournal');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_repository->shouldReceive('update')->andReturn($journal);
$this->action('POST', 'TransactionController@update', $journal->id);
$this->assertResponseStatus(302);
}
public function testUpdateFailed()
{
$journal = f::create('TransactionJournal');
// for binding
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($journal->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$journal->description = null;
$this->_repository->shouldReceive('update')->andReturn($journal);
$this->action('POST', 'TransactionController@update', $journal->id);
$this->assertResponseStatus(302);
}
}

View File

@@ -1,167 +0,0 @@
<?php
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class UserControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class UserControllerTest extends TestCase
{
protected $_user;
protected $_users;
protected $_email;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_user = m::mock('User', 'Eloquent');
$this->_users = $this->mock('Firefly\Storage\User\UserRepositoryInterface');
$this->_email = $this->mock('Firefly\Helper\Email\EmailHelperInterface');
}
public function tearDown()
{
m::close();
}
public function testLogin()
{
$this->action('GET', 'UserController@login');
$this->assertResponseOk();
}
public function testLogout()
{
$this->action('GET', 'UserController@logout');
$this->assertResponseStatus(302);
}
public function testPostLogin()
{
$input = [
'email' => 'bla@bla',
'password' => 'something',
];
Auth::shouldReceive('attempt')->with($input, false)->andReturn(true);
$this->action('POST', 'UserController@postLogin', $input);
$this->assertResponseStatus(302);
}
public function testPostLoginFails()
{
$this->action('POST', 'UserController@postLogin');
$this->assertResponseOk();
}
public function testPostRegister()
{
Config::set('auth.allow_register', true);
$user = f::create('User');
$this->_users->shouldReceive('register')->andReturn($user);
$this->_email->shouldReceive('sendPasswordMail')->with($user);
$this->action('POST', 'UserController@postRegister');
$this->assertResponseOk();
}
public function testPostRegisterFails()
{
Config::set('auth.allow_register', true);
$this->_users->shouldReceive('register')->andReturn(false);
$this->action('POST', 'UserController@postRegister');
$this->assertResponseOk();
}
public function testPostRegisterNotAllowed()
{
Config::set('auth.allow_register', false);
$this->action('POST', 'UserController@postRegister');
$this->assertResponseOk();
}
public function testPostRegisterVerify()
{
Config::set('auth.allow_register', true);
Config::set('auth.verify_mail', true);
$user = f::create('User');
$this->_users->shouldReceive('register')->andReturn($user);
$this->_email->shouldReceive('sendVerificationMail')->with($user);
$this->action('POST', 'UserController@postRegister');
$this->assertResponseOk();
}
public function testPostRemindme()
{
$user = f::create('User');
Config::set('auth.verify_reset', true);
$this->_users->shouldReceive('findByEmail')->andReturn($user);
$this->_email->shouldReceive('sendResetVerification');
$this->action('POST', 'UserController@postRemindme');
$this->assertResponseOk();
}
public function testPostRemindmeNoVerify()
{
$user = f::create('User');
Config::set('auth.verify_reset', false);
$this->_users->shouldReceive('findByEmail')->andReturn($user);
$this->_email->shouldReceive('sendPasswordMail');
$this->action('POST', 'UserController@postRemindme');
$this->assertResponseOk();
}
public function testPostRemindmeFails()
{
Config::set('auth.verify_reset', true);
$this->_users->shouldReceive('findByEmail')->andReturn(false);
$this->action('POST', 'UserController@postRemindme');
$this->assertResponseOk();
}
public function testRegister()
{
$this->action('GET', 'UserController@register');
$this->assertResponseOk();
}
public function testRegisterNotAllowed()
{
Config::set('auth.allow_register', false);
$this->action('GET', 'UserController@register');
$this->assertResponseOk();
}
public function testRemindme()
{
$this->action('GET', 'UserController@remindme');
$this->assertResponseOk();
}
public function testReset()
{
$user = f::create('User');
$this->_users->shouldReceive('findByReset')->andReturn($user);
$this->_email->shouldReceive('sendPasswordMail');
$this->action('GET', 'UserController@reset');
$this->assertResponseOk();
}
public function testResetNoUser()
{
$this->_users->shouldReceive('findByReset')->andReturn(false);
$this->action('GET', 'UserController@reset');
$this->assertResponseOk();
}
}

View File

@@ -1,12 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'Account',
[
'user_id' => 'factory|User',
'account_type_id' => 'factory|AccountType',
'name' => 'word',
'active' => 'boolean'
]
);

View File

@@ -1,10 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'AccountType',
[
'type' => 'unique:word',
'editable' => 1
]
);

View File

@@ -1,11 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'Budget',
[
'name' => 'word',
'user_id' => 'factory|User',
'class' => 'Budget'
]
);

View File

@@ -1,11 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'Category',
[
'name' => 'word',
'user_id' => 'factory|User',
'class' => 'Category'
]
);

View File

@@ -1,11 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'Component',
[
'name' => 'word',
'user_id' => 'factory|User',
'class' => 'Component'
]
);

View File

@@ -1,26 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
Facade::define(
'Limit',
[
'component_id' => 'factory|Budget',
'startdate' => function () {
$start = new Carbon;
$start->startOfMonth();
return $start;
},
'amount' => 100,
'repeats' => 'boolean',
'repeat_freq' => function () {
$frequencies = ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'];
return $frequencies[rand(0, 5)];
}
]
);

View File

@@ -1,28 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
Facade::define(
'LimitRepetition',
[
'limit_id' => 'factory|Limit',
'startdate' => function () {
$start = new Carbon;
$start->startOfMonth();
return $start;
},
'enddate' => function () {
$end = new Carbon;
$end->endOfMonth();
return $end;
},
'amount' => 100
]
);

View File

@@ -1,32 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
Facade::define(
'Piggybank',
[
'account_id' => 'factory|Account',
'name' => 'word',
'targetamount' => 'integer',
'startdate' => function () {
$start = new Carbon;
$start->startOfMonth();
return $start;
},
'targetdate' => function () {
$end = new Carbon;
$end->endOfMonth();
return $end;
},
'repeats' => 0,
'rep_length' => null,
'rep_times' => 0,
'rep_every' => 0,
'reminder' => null,
'reminder_skip' => 0,
'order' => 1,
]
);

View File

@@ -1,14 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
Facade::define(
'PiggybankEvent',
[
'piggybank_id' => 'factory|Piggybank',
'date' => new Carbon,
'amount' => 10
]
);

View File

@@ -1,25 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
Facade::define(
'PiggybankRepetition',
[
'piggybank_id' => 'factory|Piggybank',
'startdate' => function () {
$start = new Carbon;
$start->startOfMonth();
return $start;
},
'targetdate' => function () {
$end = new Carbon;
$end->endOfMonth();
return $end;
},
'currentamount' => 200
]
);

View File

@@ -1,12 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'Preference',
[
'user_id' => 'factory|User',
'name' => 'word',
'data' => 'word'
]
);

View File

@@ -1,23 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
// TODO better factory.
Facade::define(
'RecurringTransaction',
[
'user_id' => 'factory|User',
'name' => 'string',
'match' => 'string',
'amount_max' => 100,
'amount_min' => 50,
'date' => new Carbon,
'active' => 'boolean',
'automatch' => 'boolean',
'repeat_freq' => 'monthly',
'skip' => 'boolean',
]
);

View File

@@ -1,15 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'Transaction',
[
'account_id' => 'factory|Account',
'piggybank_id' => null,
'transaction_journal_id' => 'factory|TransactionJournal',
'description' => 'string',
'amount' => 'integer:5',
]
);

View File

@@ -1,11 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'TransactionCurrency',
[
'code' => 'EUR'
]
);

View File

@@ -1,17 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade;
Facade::define(
'TransactionJournal',
[
'transaction_type_id' => 'factory|TransactionType',
'transaction_currency_id' => 'factory|TransactionCurrency',
'description' => 'word',
'completed' => 'boolean',
'user_id' => 'factory|User',
'date' => new Carbon
]
);

View File

@@ -1,15 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'TransactionType',
[
'type' => function () {
$types = ['Withdrawal', 'Deposit', 'Transfer', 'Opening balance'];
return $types[rand(0, 3)];
}
]
);

View File

@@ -1,17 +0,0 @@
<?php
use League\FactoryMuffin\Facade;
Facade::define(
'User',
[
'email' => 'safeEmail',
'password' => function () {
return \Str::random(60);
},
'reset' => function () {
return \Str::random(32);
},
'remember_token' => null,
'migrated' => 'boolean'
]
);

View File

@@ -1,417 +0,0 @@
<?php
use Carbon\Carbon;
use League\FactoryMuffin\Facade as f;
/**
* Class ModelTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
*/
class ModelTest extends TestCase
{
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
}
public function tearDown()
{
Mockery::close();
}
public function testAccount()
{
$account = f::create('Account');
$user = f::create('User');
$type = f::create('AccountType');
$piggybank = f::create('Piggybank');
$account->user()->associate($user);
$account->accounttype()->associate($type);
$account->piggybanks()->save($piggybank);
$this->assertEquals($account->predict(new Carbon), null);
$this->assertEquals($account->balance(new Carbon), null);
$this->assertEquals($account->user_id, $user->id);
$this->assertEquals($piggybank->account_id, $account->id);
$this->assertEquals($account->account_type_id, $type->id);
}
public function testAccountType()
{
$account = f::create('Account');
$type = f::create('AccountType');
$type->accounts()->save($account);
$this->assertEquals($account->account_type_id, $type->id);
}
public function testBudget()
{
$budget = f::create('Budget');
$limit = f::create('Limit');
$journal = f::create('TransactionJournal');
$budget->limits()->save($limit);
$budget->transactionjournals()->save($journal);
$this->assertEquals($limit->component_id, $budget->id);
$this->assertEquals($journal->budgets()->first()->id, $budget->id);
}
public function testCategory()
{
$category = f::create('Category');
$journal = f::create('TransactionJournal');
$category->transactionjournals()->save($journal);
$this->assertEquals($journal->categories()->first()->id, $category->id);
}
public function testComponent()
{
$component = f::create('Component');
$limit = f::create('Limit');
$component->limits()->save($limit);
$component->save();
$transaction = f::create('Transaction');
$journal = f::create('TransactionJournal');
$user = f::create('User');
$component->transactions()->save($transaction);
$component->transactionjournals()->save($journal);
$component->user()->associate($user);
$this->assertEquals($transaction->components()->first()->id, $component->id);
$this->assertEquals($journal->components()->first()->id, $component->id);
$this->assertEquals($limit->component()->first()->id, $component->id);
$this->assertEquals($component->user_id, $user->id);
}
public function testLimit()
{
$limit = f::create('Limit');
$budget = f::create('Budget');
$rep = f::create('LimitRepetition');
$limit->budget()->associate($budget);
$limit->limitrepetitions()->save($rep);
$rep->save();
$limit->save();
$this->assertEquals($rep->limit_id, $limit->id);
$this->assertEquals($limit->component_id, $budget->id);
// create repetition:
$start = new Carbon;
$list = ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'];
foreach ($list as $entry) {
$limit->repeat_freq = $entry;
$limit->createRepetition($start);
}
}
// /**
// * @expectedException \Firefly\Exception\FireflyException
// */
// public function testLimitrepetition()
// {
// $limit = f::create('Limit');
// $rep = f::create('LimitRepetition');
// $budget = f::create('Budget');
// $journal = f::create('TransactionJournal');
// $one = f::create('Transaction');
// $two = f::create('Transaction');
// $one->amount = 300;
// $two->amount = -300;
//
// $rep->limit()->associate($limit);
// $limit->budget()->associate($budget);
// $journal->transactions()->save($one);
// $journal->transactions()->save($two);
// $journal->budgets()->save($budget);
//
// $this->assertEquals(($rep->amount - 300), $rep->left());
//
// // repeat frequency (not present) for periodOrder
// $testDate = new Carbon;
// $testDate->startOfMonth();
// $rep->repeat_freq = null;
//
// // this test will FAIL because nowadays the $rep has a random thing.
// // TODO
//
//
// //$this->assertEquals($testDate->format('Ymd') . '-3', $rep->periodOrder());
//
// // repeat frequency (present) for periodOrder
// $list = ['yearly', 'half-year', 'quarterly', 'monthly', 'weekly', 'daily'];
// foreach ($list as $index => $entry) {
// $rep->repeat_freq = $entry;
// $this->assertEquals($testDate->format('Ymd') . '-' . $index, $rep->periodOrder());
// }
//
// // repeat freq (invalid) for periodOrder
// $rep->repeat_freq = 'bad';
// $rep->periodOrder();
//
// }
/**
* @expectedException \Firefly\Exception\FireflyException
*/
public function testLimitrepetitionContinued()
{
$limit = f::create('Limit');
$rep = f::create('LimitRepetition');
$budget = f::create('Budget');
$journal = f::create('TransactionJournal');
$one = f::create('Transaction');
$two = f::create('Transaction');
$one->amount = 300;
$two->amount = -300;
$rep->limit()->associate($limit);
$limit->budget()->associate($budget);
$journal->transactions()->save($one);
$journal->transactions()->save($two);
$journal->budgets()->save($budget);
// repeat frequency (not present) for periodShow
$testDate = new Carbon;
$testDate->startOfMonth();
$rep->repeat_freq = null;
// TODO cannot test this with the new factories.
// $this->assertEquals($testDate->format('F Y'), $rep->periodShow());
// repeat frequency (present) for periodOrder
$list = ['yearly', 'half-year', 'quarterly', 'monthly', 'weekly', 'daily'];
foreach ($list as $entry) {
$rep->repeat_freq = $entry;
$this->assertGreaterThan(0, strlen($rep->periodShow()));
}
// repeat freq (invalid) for periodOrder
$rep->repeat_freq = 'bad';
$rep->periodShow();
}
public function testPiggybank()
{
$piggy = f::create('Piggybank');
$account = f::create('Account');
$piggy->account()->associate($account);
$this->assertEquals($account->id, $piggy->account_id);
$repetition = f::create('PiggybankRepetition');
$repetition->piggybank()->associate($piggy);
$repetition->save();
$list = ['day', 'week', 'month', 'year'];
// with a start date, so next reminder is built from a loop:
foreach ($list as $reminder) {
$piggy->reminder = $reminder;
$repetition->save();
$piggy->nextReminderDate();
}
// set the reminder period to be invalid, should return NULL
$piggy->reminder = 'invalid';
$piggy->save();
$this->assertNull($piggy->nextReminderDate());
// set the start date to zero, give a valid $reminder, retry:
$repetition->startdate = null;
$piggy->reminder = 'month';
$repetition->save();
foreach ($list as $reminder) {
$piggy->reminder = $reminder;
$repetition->save();
$piggy->nextReminderDate();
}
// set the reminder to be invalid again:
$piggy->reminder = 'invalid';
$piggy->save();
$piggy->nextReminderDate();
// set it to be NULL
$piggy->reminder = null;
$piggy->save();
$piggy->nextReminderDate();
// remove the repetition, retry:
$piggy->reminder = 'month';
$piggy->save();
$repetition->delete();
$piggy->nextReminderDate();
$event = f::create('PiggybankEvent');
$event->piggybank()->associate($piggy);
$event->save();
$this->assertEquals($piggy->piggybankevents()->first()->id, $event->id);
$this->assertNull($piggy->repetitionForDate(new Carbon('2012-02-02')));
$transaction = f::create('Transaction');
$transaction->piggybank()->associate($piggy);
$transaction->save();
$this->assertEquals($transaction->piggybank_id, $piggy->id);
$this->assertEquals($piggy->transactions()->first()->id, $transaction->id);
$repetition->pct();
}
public function testPreference()
{
$pref = f::create('Preference');
$user = f::create('User');
$pref->user()->associate($user);
$this->assertEquals($pref->user_id, $user->id);
$pref->data = 'Hello';
$this->assertEquals($pref->data, 'Hello');
}
public function testRecurringtransaction()
{
$rec = f::create('RecurringTransaction');
$user = f::create('User');
$rec->user()->associate($user);
$this->assertEquals($rec->user_id, $user->id);
$list = ['yearly', 'half-year', 'quarterly', 'monthly', 'weekly', 'daily'];
foreach ($list as $entry) {
$start = clone $rec->date;
$rec->repeat_freq = $entry;
$end = $rec->next();
$this->assertTrue($end > $start);
}
}
public function testTransaction()
{
$transaction = f::create('Transaction');
$journal = f::create('TransactionJournal');
$component = f::create('Component');
$budget = f::create('Budget');
$category = f::create('Category');
$account = f::create('Account');
$piggy = f::create('Piggybank');
$transaction->transactionJournal()->associate($journal);
$this->assertEquals($transaction->transaction_journal_id, $journal->id);
$transaction->components()->save($component);
$this->assertEquals($transaction->components()->first()->id, $component->id);
$transaction->budgets()->save($budget);
$this->assertEquals($transaction->budgets()->first()->id, $budget->id);
$transaction->categories()->save($category);
$this->assertEquals($transaction->categories()->first()->id, $category->id);
$transaction->account()->associate($account);
$this->assertEquals($transaction->account_id, $account->id);
$transaction->piggybank()->associate($piggy);
$this->assertEquals($transaction->piggybank_id, $piggy->id);
}
public function testTransactionCurrency()
{
$cur = f::create('TransactionCurrency');
$journal = f::create('TransactionJournal');
$cur->transactionjournals()->save($journal);
$journal->save();
$cur->save();
$this->assertEquals($cur->id, $journal->transaction_currency_id);
}
public function testTransactionJournal()
{
$journal = f::create('TransactionJournal');
$type = f::create('TransactionType');
$user = f::create('User');
$cur = f::create('TransactionCurrency');
$transaction = f::create('Transaction');
$component = f::create('Component');
$budget = f::create('Budget');
$category = f::create('Category');
$journal->transactionType()->associate($type);
$this->assertEquals($type->id, $journal->transaction_type_id);
$journal->user()->associate($user);
$this->assertEquals($user->id, $journal->user_id);
$journal->transactionCurrency()->associate($cur);
$this->assertEquals($cur->id, $journal->transaction_currency_id);
$journal->transactions()->save($transaction);
$this->assertEquals($journal->transactions()->first()->id, $transaction->id);
$journal->components()->save($component);
$this->assertEquals($journal->components()->first()->id, $component->id);
$journal->budgets()->save($budget);
$this->assertEquals($journal->budgets()->first()->id, $budget->id);
$journal->categories()->save($category);
$this->assertEquals($journal->categories()->first()->id, $category->id);
}
public function testTransactionType()
{
$journal = f::create('TransactionJournal');
$type = f::create('TransactionType');
$type->transactionjournals()->save($journal);
$this->assertEquals($type->transactionJournals()->first()->id, $journal->id);
}
public function testUser()
{
$user = f::create('User');
$account = f::create('Account');
$bud = f::create('Budget');
$cat = f::create('Category');
$comp = f::create('Component');
$pref = f::create('Preference');
$rec = f::create('RecurringTransaction');
$journal = f::create('TransactionJournal');
$piggy = f::create('Piggybank');
$user->accounts()->save($account);
$this->assertEquals($account->id, $user->accounts()->first()->id);
$user->components()->save($comp);
$this->assertEquals($comp->id, $user->components()->first()->id);
$user->budgets()->save($bud);
$this->assertEquals($bud->id, $user->budgets()->first()->id);
$user->categories()->save($cat);
$this->assertEquals($cat->id, $user->categories()->first()->id);
$user->preferences()->save($pref);
$this->assertEquals($pref->id, $user->preferences()->first()->id);
$user->recurringtransactions()->save($rec);
$this->assertEquals($rec->id, $user->recurringtransactions()->first()->id);
$user->transactionjournals()->save($journal);
$this->assertEquals($journal->id, $user->transactionjournals()->first()->id);
$piggy->account()->associate($account);
$piggy->save();
$this->assertCount(1, $user->piggybanks()->get());
}
}

View File

@@ -72,21 +72,21 @@
</td>
</tr>
@endif
@if(count($show['statistics']['categories']) > 0)
@if(isset($show['statistics']['Category']) && count($show['statistics']['Category']) > 0)
<tr>
<td>Related categories</td>
<td>
@foreach($show['statistics']['categories'] as $cat)
@foreach($show['statistics']['Category'] as $cat)
<a href="{{route('categories.show',$cat->id)}}" class="btn btn-default btn-xs">{{{$cat->name}}}</a>
@endforeach
</td>
</tr>
@endif
@if(count($show['statistics']['budgets']) > 0)
@if(isset($show['statistics']['Budget']) && count($show['statistics']['Budget']) > 0)
<tr>
<td>Related budgets</td>
<td>
@foreach($show['statistics']['budgets'] as $bud)
@foreach($show['statistics']['Budget'] as $bud)
<a href="{{route('budgets.show',$bud->id)}}?useSession=true" class="btn btn-default btn-xs">{{{$bud->name}}}</a>
@endforeach
</td>

View File

@@ -81,7 +81,7 @@
</div>
<div class="col-sm-3">
<small>
<a href="{{route('budgets.show',$budget->id)}}?rep={{$rep->id}}">
<a href="{{route('budgets.show',$budget->id,$rep->id)}}">
{{$rep->periodShow()}}
</a>
</small>

View File

@@ -35,7 +35,7 @@
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h3><a href="{{route('transactions.index')}}?startdate={{$entry['start']->format('Y-m-d')}}&amp;enddate={{$entry['end']->format('Y-m-d')}}">{{$entry['date']}}</a>
<a class="btn btn-default btn-xs" href ="{{route('budgets.limits.create')}}?startdate={{$entry['dateObject']->format('Y-m-d')}}"><span class="glyphicon glyphicon-plus-sign"></span> Create a new envelope for {{$entry['date']}}</a>
<a class="btn btn-default btn-xs" href ="{{route('budgets.limits.create')}}?startdate={{$entry['start']->format('Y-m-d')}}"><span class="glyphicon glyphicon-plus-sign"></span> Create a new envelope for {{$entry['date']}}</a>
</h3>
<table class="table table-bordered table-striped">
<tr>
@@ -53,7 +53,7 @@
</div>
</td>
<td>
<a href="{{route('budgets.show',$repetition->limit->budget->id)}}?rep={{$repetition->id}}">
<a href="{{route('budgets.show',[$repetition->limit->budget->id,$repetition->id])}}">
{{{$repetition->limit->budget->name}}}
</a>
</td>

View File

@@ -6,39 +6,37 @@
<small>Overview for budget "{{{$budget->name}}}"</small>
</h1>
<p class="lead">Budgets can help you cut back on spending.</p>
@if($view == 1)
<!-- warning for selected limit -->
@if(isset($filters[0]) && is_object($filters[0]) && get_class($filters[0]) == 'Limit')
<p class="bg-primary" style="padding:15px;">
This view is filtered to show only the envelope from
{{{$repetitions[0]['limitrepetition']->periodShow()}}},
which contains {{mf($repetitions[0]['limit']->amount,false)}}.
</p>
<p class="bg-info" style="padding:15px;">
<a href="{{route('budgets.show',$budget->id)}}" class="text-info">Reset the filter(s).</a>
</p>
@endif
@if($view == 2)
<!-- warning for non-caught only -->
@if(isset($filters[0]) && $filters[0] == 'no_envelope')
<p class="bg-primary" style="padding:15px;">
This view is filtered to show transactions not in an envelope only.
</p>
<p class="bg-info" style="padding:15px;">
<a href="{{route('budgets.show',$budget->id)}}" class="text-info">Reset the filter(s).</a>
</p>
@endif
@if($view == 3)
<!-- warning for session date -->
@if($useSessionDates == true)
<p class="bg-primary" style="padding:15px;">
This view is filtered to only show transactions between {{Session::get('start')->format('d M Y')}}
and {{Session::get('end')->format('d M Y')}}.
</p>
<p class="bg-info" style="padding:15px;">
<a href="{{route('budgets.show',$budget->id)}}" class="text-info">Reset the filter(s).</a>
</p>
@endif
@if($view != 4)
<p class="bg-info" style="padding:15px;">
<a class="btn btn-default btn-sm" href="{{route('budgets.show',$budget->id)}}">Reset the filter</a>
</p>
@endif
</div>
</div>
@@ -46,17 +44,22 @@
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div id="chart"></div>
@if(isset($filters[0]) && is_object($filters[0]) && get_class($filters[0]) == 'Limit')
@if($view == 1)
<div id="instr" data-type="envelope" data-envelope="{{$repetitions[0]['limitrepetition']->id}}"></div>
@elseif(isset($filters[0]) && $filters[0] == 'no_envelope')
<div id="instr" data-type="no_envelope" data-budget="{{$budget->id}}"></div>
@elseif($useSessionDates == true)
<div id="instr" data-type="session" data-budget="{{$budget->id}}"></div>
@else
<div id="instr" data-type="default" data-budget="{{$budget->id}}"></div>
@endif
@if($view == 2)
<div id="instr" data-type="no_envelope" data-budget="{{$budget->id}}"></div>
@endif
@if($view == 3)
<div id="instr" data-type="session" data-budget="{{$budget->id}}"></div>
@endif
@if($view == 4)
<div id="instr" data-type="default" data-budget="{{$budget->id}}"></div>
@endif
</div>
</div>
@@ -73,7 +76,7 @@
{{$repetition['date']}}</a> <small>paginated</small></h4>
@else
<h4>
<a href="{{route('budgets.show',$budget->id)}}?rep={{$repetition['limitrepetition']->id}}">
<a href="{{route('budgets.show',$budget->id,$repetition['limitrepetition']->id)}}">
{{$repetition['date']}}
</a>
</h4>
@@ -100,13 +103,18 @@
@stop
@section('scripts')
@if(isset($filters[0]) && is_object($filters[0]) && get_class($filters[0]) == 'Limit')
@if($view == 1)
<?php echo javascript_include_tag('budgets-limit'); ?>
@elseif(isset($filters[0]) && $filters[0] == 'no_envelope')
@endif
@if($view == 2)
<?php echo javascript_include_tag('budgets-nolimit'); ?>
@elseif($useSessionDates == true)
@endif
@if($view == 3)
<?php echo javascript_include_tag('budgets-session'); ?>
@else
@endif
@if($view == 4)
<?php echo javascript_include_tag('budgets-default'); ?>
@endif

View File

@@ -24,7 +24,7 @@
</div>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12">
<h2><a href="#">Migrate from Firefly II</a></h2>
<h2><a href="{{route('migrate.index')}}">Migrate from Firefly II</a></h2>
<p>
Use this option if you have a JSON file from your current Firefly II installation.

View File

@@ -38,6 +38,10 @@
<a href="{{route('categories.show',$component->id)}}?highlight={{$journal->id}}"><span class="glyphicon glyphicon-tag" title="Category: {{{$component->name}}}"></span></a>
@endif
@endforeach
<!-- recurring transaction -->
@if(!is_null($journal->recurringTransaction))
<a href="{{route('recurring.show',$journal->recurring_transaction_id)}}" title="{{{$journal->recurringTransaction->name}}}"><span title="{{{$journal->recurringTransaction->name}}}" class="glyphicon glyphicon-refresh"></span></a>
@endif
</td>
<td>
{{$journal->date->format('d F Y')}}

Some files were not shown because too many files have changed in this diff Show More