diff --git a/.coveralls.yml b/.coveralls.yml index 482521d6ec..68c3d23770 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1,2 +1,3 @@ src_dir: . -coverage_clover: tests/_output/coverage.xml \ No newline at end of file +coverage_clover: tests/_output/coverage.xml +json_path: tests/_output/coveralls-upload.json \ No newline at end of file diff --git a/.gitignore b/.gitignore index d0be83396b..71d8f61ce0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ /bootstrap/compiled.php /vendor composer.phar -composer.lock .env.*.php .env.php .DS_Store @@ -14,8 +13,13 @@ index.html* app/storage/firefly-export* .vagrant firefly-iii-import-*.json - tests/_output/* testing.sqlite -c3.php _ide_helper_models.php +clean.sqlite +tests/acceptance/AcceptanceTester.php +tests/functional/FunctionalTester.php +tests/unit/UnitTester.php +pi.php +tests/_data/db.sqlite +tests/_data/dump.sql diff --git a/.travis.yml b/.travis.yml index 835ec484b9..7638995c02 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,13 +3,14 @@ language: php php: - 5.5 - 5.6 - - hhvm install: - composer install script: - - php vendor/bin/codecept run + - ./tests/_data/db.sh + - php vendor/bin/codecept build + - php vendor/bin/codecept run --coverage --coverage-xml after_script: - php vendor/bin/coveralls \ No newline at end of file diff --git a/README.md b/README.md index 6d44b33cf8..25c2f0d92b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ Firefly III =========== -[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=master)](https://travis-ci.org/JC5/firefly-iii) -![Still maintained?](http://stillmaintained.com/JC5/firefly-iii.png) +[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii) +[![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/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) [![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii) [![Total Downloads](https://poser.pugx.org/grumpydictator/firefly-iii/downloads.svg)](https://packagist.org/packages/grumpydictator/firefly-iii) @@ -17,13 +18,15 @@ laptop and [Firefly II](https://github.com/JC5/Firefly) is live. ## Current features -- [A double-entry bookkeeping system](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system). +- [A double-entry bookkeeping system](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system); - You can store, edit and remove withdrawals, deposits and transfers. This allows you full financial management; - It's possible to create, change and manage money using _budgets_; - Organize transactions using categories; - Save towards a goal using piggy banks; - Predict and anticipate large expenses using "repeated expenses" (ie. yearly taxes); -- Predict and anticipate bills using "recurring transactions" (rent for example). +- Predict and anticipate bills using "recurring transactions" (rent for example); +- View basic income / expense reports. +- Lots of help text in case you don't get it; Everything is organised: @@ -37,15 +40,13 @@ Everything is organised: Firefly III will feature, but does not feature yet: - Financial reporting showing you how well you are doing; -- Lots of help text in case you don't get it; - More control over other resources outside of personal finance - Accounts shared with a partner (household accounts) - Debts - Credit cards -- More test-coverage (aka: actual test coverage); +- More test-coverage; - Firefly will be able to split transactions; a single purchase can be split in multiple entries, for more fine-grained control. - Firefly will be able to join transactions. -- Transfers and transactions are combined into one internal datatype which is more consistent with what you're actually doing: moving money from A to B. The fact that A or B or both are yours should not matter. - Any other features I might not have thought of. Some stuff has been removed: @@ -64,13 +65,9 @@ Some stuff has been removed: ![Reports](http://i.imgur.com/EnEIyQI.png) ## Current state -I have the basics up and running. Test coverage is currently non-existent. +I have the basics up and running. Test coverage is currently coming, slowly. Although I have not checked extensively, some forms and views have CSRF vulnerabilities. This is because not all views escape all characters by default. Will be fixed. -The current layout / look & feel is a pretty basic Bootstrap3 template. I am currently working on a more consistent, -expanded layout which will feature shiny AJAX things and data tables and all the Web 3.0 goodies you've come to expect -from social media sites. - Questions, ideas or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)! \ No newline at end of file diff --git a/app/breadcrumbs.php b/app/breadcrumbs.php index 9772319edf..3269c6e773 100644 --- a/app/breadcrumbs.php +++ b/app/breadcrumbs.php @@ -90,7 +90,7 @@ Breadcrumbs::register( $breadcrumbs->push($budget->name, route('budgets.show', $budget->id)); if (!is_null($repetition)) { $breadcrumbs->push( - DateKit::periodShow($repetition->startdate, $repetition->limit->repeat_freq), route('budgets.show', $budget->id, $repetition->id) + DateKit::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id) ); } } diff --git a/app/commands/Cleanup.php b/app/commands/Cleanup.php index 2e5c889068..76b734fe53 100644 --- a/app/commands/Cleanup.php +++ b/app/commands/Cleanup.php @@ -1,9 +1,12 @@ info('Cleared compiled...'); Artisan::call('ide-helper:generate'); $this->info('IDE helper, done...'); - Artisan::call('ide-helper:models', ['write']); + Artisan::call('ide-helper:models', ['nowrite']); $this->info('IDE models, done...'); Artisan::call('optimize'); $this->info('Optimized...'); diff --git a/app/config/homestead/database.php b/app/config/homestead/database.php index de7f714bdf..29737579f8 100644 --- a/app/config/homestead/database.php +++ b/app/config/homestead/database.php @@ -2,22 +2,7 @@ return [ - /* - |-------------------------------------------------------------------------- - | Database Connections - |-------------------------------------------------------------------------- - | - | Here are each of the database connections setup for your application. - | Of course, examples of configuring each database platform that is - | supported by Laravel is shown below to make development simple. - | - | - | All database work in Laravel is done through the PHP PDO facilities - | so make sure you have the driver for your particular database of - | choice installed on your machine before you begin development. - | - */ - + 'default' => 'mysql', 'connections' => [ 'mysql' => [ @@ -30,6 +15,11 @@ return [ 'collation' => 'utf8_unicode_ci', 'prefix' => '', ], + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => realpath(__DIR__.'/../../../tests/_data/testing.sqlite'), + 'prefix' => '' + ], 'pgsql' => [ 'driver' => 'pgsql', diff --git a/app/config/packages/rcrowe/twigbridge/extensions.php b/app/config/packages/rcrowe/twigbridge/extensions.php deleted file mode 100644 index 8f99eb097e..0000000000 --- a/app/config/packages/rcrowe/twigbridge/extensions.php +++ /dev/null @@ -1,134 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Configuration options for the built-in extensions. - */ -return [ - - /* - |-------------------------------------------------------------------------- - | Extensions - |-------------------------------------------------------------------------- - | - | Enabled extensions. - | - | `Twig_Extension_Debug` is enabled automatically if twig.debug is TRUE. - | - */ - 'enabled' => [ - 'TwigBridge\Extension\Loader\Facades', - 'TwigBridge\Extension\Loader\Filters', - 'TwigBridge\Extension\Loader\Functions', - - 'TwigBridge\Extension\Laravel\Auth', - 'TwigBridge\Extension\Laravel\Config', - 'TwigBridge\Extension\Laravel\Form', - 'TwigBridge\Extension\Laravel\Html', - 'TwigBridge\Extension\Laravel\Input', - 'TwigBridge\Extension\Laravel\Session', - 'TwigBridge\Extension\Laravel\String', - 'TwigBridge\Extension\Laravel\Translator', - 'TwigBridge\Extension\Laravel\Url', - - // 'TwigBridge\Extension\Laravel\Legacy\Facades', - ], - - /* - |-------------------------------------------------------------------------- - | Facades - |-------------------------------------------------------------------------- - | - | Available facades. Access like `{{ Config.get('foo.bar') }}`. - | - | Each facade can take an optional array of options. To mark the whole facade - | as safe you can set the option `'is_safe' => true`. Setting the facade as - | safe means that any HTML returned will not be escaped. - | - | It is advisable to not set the whole facade as safe and instead mark the - | each appropriate method as safe for security reasons. You can do that with - | the following syntax: - | - | - | 'Form' => [ - | 'is_safe' => [ - | 'open' - | ] - | ] - | - | - | The values of the `is_safe` array must match the called method on the facade - | in order to be marked as safe. - | - */ - 'facades' => [], - - /* - |-------------------------------------------------------------------------- - | Functions - |-------------------------------------------------------------------------- - | - | Available functions. Access like `{{ secure_url(...) }}`. - | - | Each function can take an optional array of options. These options are - | passed directly to `Twig_SimpleFunction`. - | - | So for example, to mark a function as safe you can do the following: - | - | - | 'link_to' => [ - | 'is_safe' => ['html'] - | ] - | - | - | The options array also takes a `callback` that allows you to name the - | function differently in your Twig templates than what it's actually called. - | - | - | 'link' => [ - | 'callback' => 'link_to' - | ] - | - | - */ - 'functions' => [], - - /* - |-------------------------------------------------------------------------- - | Filters - |-------------------------------------------------------------------------- - | - | Available filters. Access like `{{ variable|filter }}`. - | - | Each filter can take an optional array of options. These options are - | passed directly to `Twig_SimpleFilter`. - | - | So for example, to mark a filter as safe you can do the following: - | - | - | 'studly_case' => [ - | 'is_safe' => ['html'] - | ] - | - | - | The options array also takes a `callback` that allows you to name the - | filter differently in your Twig templates than what is actually called. - | - | - | 'snake' => [ - | 'callback' => 'snake_case' - | ] - | - | - */ - 'filters' => [], - -]; diff --git a/app/config/packages/rcrowe/twigbridge/twig.php b/app/config/packages/rcrowe/twigbridge/twig.php deleted file mode 100644 index 343e9e1e14..0000000000 --- a/app/config/packages/rcrowe/twigbridge/twig.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Illuminate\Support\Facades\Config; - -/** - * Configuration options for Twig. - */ -return [ - - /* - |-------------------------------------------------------------------------- - | Extension - |-------------------------------------------------------------------------- - | - | File extension for Twig view files. - | - */ - 'extension' => 'twig', - - /* - |-------------------------------------------------------------------------- - | Accepts all Twig environment configuration options - |-------------------------------------------------------------------------- - | - | http://twig.sensiolabs.org/doc/api.html#environment-options - | - */ - 'environment' => [ - - // When set to true, the generated templates have a __toString() method - // that you can use to display the generated nodes. - // default: false - 'debug' => Config::get('app.debug', false), - - // The charset used by the templates. - // default: utf-8 - 'charset' => 'utf-8', - - // The base template class to use for generated templates. - // default: TwigBridge\Twig\Template - 'base_template_class' => 'TwigBridge\Twig\Template', - - // An absolute path where to store the compiled templates, or false to disable caching. If null - // then the cache file path is used. - // default: cache file storage path - 'cache' => null, - - // When developing with Twig, it's useful to recompile the template - // whenever the source code changes. If you don't provide a value - // for the auto_reload option, it will be determined automatically based on the debug value. - 'auto_reload' => true, - - // If set to false, Twig will silently ignore invalid variables - // (variables and or attributes/methods that do not exist) and - // replace them with a null value. When set to true, Twig throws an exception instead. - // default: false - 'strict_variables' => false, - - // If set to true, auto-escaping will be enabled by default for all templates. - // default: true - 'autoescape' => true, - - // A flag that indicates which optimizations to apply - // (default to -1 -- all optimizations are enabled; set it to 0 to disable) - 'optimizations' => -1, - ], - - /* - |-------------------------------------------------------------------------- - | Global variables - |-------------------------------------------------------------------------- - | - | These will always be passed in and can be accessed as Twig variables. - | NOTE: these will be overwritten if you pass data into the view with the same key. - | - */ - 'globals' => [], - -]; diff --git a/app/config/testing/cache.php b/app/config/testing/cache.php index 729ae3a825..fef1e78b52 100644 --- a/app/config/testing/cache.php +++ b/app/config/testing/cache.php @@ -1,20 +1,3 @@ 'array', - -]; +return ['driver' => 'array',]; diff --git a/app/config/testing/database.php b/app/config/testing/database.php index dce7200371..3517df8d20 100644 --- a/app/config/testing/database.php +++ b/app/config/testing/database.php @@ -4,7 +4,7 @@ return [ 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', - 'database' => 'tests/_data/testing.sqlite', + 'database' => realpath(__DIR__.'/../../../tests/_data/db.sqlite'), 'prefix' => '' ] diff --git a/app/config/testing/session.php b/app/config/testing/session.php index 46bf726a27..fef1e78b52 100644 --- a/app/config/testing/session.php +++ b/app/config/testing/session.php @@ -1,21 +1,3 @@ 'array', - -]; +return ['driver' => 'array',]; diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index b4fe3cd03d..190df02a5d 100644 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -1,6 +1,6 @@ withInput(); - } - return Redirect::route('accounts.index', $data['what']); + return Redirect::route('accounts.create', $data['what'])->withInput(); } /** @@ -210,6 +206,7 @@ class AccountController extends BaseController $data = Input::except('_token'); $data['what'] = $this->_shortNamesByFullName[$account->accountType->type]; + // always validate: $messages = $this->_repository->validate($data); @@ -234,11 +231,8 @@ class AccountController extends BaseController if ($data['post_submit_action'] == 'update') { return Redirect::route('accounts.index', $data['what']); } - // go back to update screen. - if ($data['post_submit_action'] == 'return_to_edit') { - return Redirect::route('accounts.edit', $account->id); - } - return Redirect::route('accounts.index', $data['what']); + // go back to update screen. + return Redirect::route('accounts.edit', $account->id)->withInput(['post_submit_action' => 'return_to_edit']); } } \ No newline at end of file diff --git a/app/controllers/BudgetController.php b/app/controllers/BudgetController.php index 3d2f95d75a..a3fa3bd014 100644 --- a/app/controllers/BudgetController.php +++ b/app/controllers/BudgetController.php @@ -1,24 +1,34 @@ _repository = $repository; + $this->_repository = $repository; + $this->_preferences = $preferences; View::share('title', 'Budgets'); View::share('mainTitleIcon', 'fa-tasks'); } @@ -31,17 +41,11 @@ class BudgetController extends BaseController */ public function amount(Budget $budget) { - $amount = intval(Input::get('amount')); - $date = Session::get('start'); - $limit = $this->_repository->updateLimitAmount($budget, $date, $amount); + $amount = intval(Input::get('amount')); + $date = Session::get('start', Carbon::now()->startOfMonth()); + $limitRepetition = $this->_repository->updateLimitAmount($budget, $date, $amount); - // try to find the limit repetition for this limit: - $repetition = $limit->limitrepetitions()->first(); - if ($repetition) { - return Response::json(['name' => $budget->name, 'repetition' => $repetition->id]); - } else { - return Response::json(['name' => $budget->name, 'repetition' => null]); - } + return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition->id]); } @@ -72,8 +76,9 @@ class BudgetController extends BaseController */ public function destroy(Budget $budget) { + Session::flash('success', 'Budget "' . e($budget->name) . '" was deleted.'); $this->_repository->destroy($budget); - Session::flash('success', 'The budget was deleted.'); + return Redirect::route('budgets.index'); @@ -86,67 +91,38 @@ class BudgetController extends BaseController */ public function edit(Budget $budget) { - $subTitle = 'Edit budget "' . $budget->name . '"'; + $subTitle = 'Edit budget "' . e($budget->name) . '"'; return View::make('budgets.edit', compact('budget', 'subTitle')); } /** + * The index of the budget controller contains all budgets and the current relevant limit repetition. + * TODO move currentRep to the repository. + * * @return $this */ public function index() { + $budgets = $this->_repository->get(); - /** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface'); - - /** @var \FireflyIII\Database\Budget $repos */ - $repos = App::make('FireflyIII\Database\Budget'); - $budgets = $repos->get(); - - // get the limits for the current month. - $date = \Session::get('start'); - $spent = 0; - /** @var \Budget $budget */ - foreach ($budgets as $budget) { - - $budget->spent = $repos->spentInMonth($budget, $date); - $spent += $budget->spent; - $budget->pct = 0; - $budget->limit = 0; - - /** @var \Limit $limit */ - foreach ($budget->limits as $limit) { - /** @var \LimitRepetition $repetition */ - foreach ($limit->limitrepetitions as $repetition) { - if ($repetition->startdate == $date) { - $budget->currentRep = $repetition; - $budget->limit = floatval($repetition->amount); - if ($budget->limit > $budget->spent) { - // not overspent: - $budget->pct = 30; - } else { - $budget->pct = 50; - } - - } - } + // loop the budgets: + $budgets->each( + function (Budget $budget) { + $budget->spent = $this->_repository->spentInMonth($budget, \Session::get('start', Carbon::now()->startOfMonth())); + $budget->currentRep = $this->_repository->getRepetitionByDate($budget, \Session::get('start', Carbon::now()->startOfMonth())); } - } + ); - $budgetAmount = $preferences->get('budgetIncomeTotal' . $date->format('FY'), 1000); - $amount = floatval($budgetAmount->data); - $overspent = $spent > $amount; - if ($overspent) { - // overspent on total amount - $spentPCT = ceil($amount / $spent * 100); - } else { - // not overspent on total amount. - $spentPCT = ceil($spent / $amount * 100); - } + $spent = $budgets->sum('spent'); + $amount = $this->_preferences->get('budgetIncomeTotal' . \Session::get('start', Carbon::now()->startOfMonth())->format('FY'), 1000)->data; + $overspent = $spent > $amount; + $spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100); + $budgetMax = $this->_preferences->get('budgetMaximum', 1000); + $budgetMaximum = $budgetMax->data; - return View::make('budgets.index', compact('budgets', 'spent', 'spentPCT', 'overspent'))->with('budgetAmount', $budgetAmount); + return View::make('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount')); } /** @@ -154,12 +130,7 @@ class BudgetController extends BaseController */ public function postUpdateIncome() { - /** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface'); - $date = Session::get('start'); - - $value = intval(Input::get('amount')); - $preferences->set('budgetIncomeTotal' . $date->format('FY'), $value); + $this->_preferences->set('budgetIncomeTotal' . Session::get('start', Carbon::now()->startOfMonth())->format('FY'), intval(Input::get('amount'))); return Redirect::route('budgets.index'); } @@ -172,124 +143,91 @@ class BudgetController extends BaseController */ public function show(Budget $budget, LimitRepetition $repetition = null) { - if (!is_null($repetition) && $repetition->limit->budget->id != $budget->id) { - App::abort(500); + if (!is_null($repetition) && $repetition->budgetLimit->budget->id != $budget->id) { + return View::make('error')->with('message', 'Invalid selection.'); } - /** @var \FireflyIII\Database\Budget $repos */ - $repos = App::make('FireflyIII\Database\Budget'); - - if (is_null($repetition)) { - // get all other repetitions: - $limits = $budget->limits()->orderBy('startdate', 'DESC')->get(); - // get all transaction journals for this budget. - $journals = $repos->getTransactionJournals($budget, 50); - - $subTitle = $budget->name; - } else { - // get nothing? i dunno - $limits = [$repetition->limit]; - // get all transaction journals for this budget and limit repetition. - $subTitle = $budget->name . ' in ' . $repetition->startdate->format('F Y'); - $journals = $repos->getTransactionJournalsInRepetition($budget, $repetition, 50); - } - $hideBudget = true; + $hideBudget = true; // used in transaction list. + $journals = $this->_repository->getJournals($budget, $repetition); + $limits = $repetition ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get(); + $subTitle = $repetition ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name); return View::make('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget')); } /** - * @return $this - * @throws FireflyException + * @return $this|\Illuminate\Http\RedirectResponse */ public function store() { - /** @var \FireflyIII\Database\Budget $repos */ - $repos = App::make('FireflyIII\Database\Budget'); - $data = Input::except('_token'); + $data = Input::except('_token'); + $data['user_id'] = Auth::user()->id; - switch ($data['post_submit_action']) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"'); - break; - case 'create_another': - case 'store': - $messages = $repos->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save budget: ' . $messages['errors']->first()); + // always validate: + $messages = $this->_repository->validate($data); - return Redirect::route('budgets.create')->withInput()->withErrors($messages['errors']); - } - // store! - $repos->store($data); - Session::flash('success', 'New budget stored!'); - - if ($data['post_submit_action'] == 'create_another') { - return Redirect::route('budgets.create'); - } else { - return Redirect::route('budgets.index'); - } - break; - case 'validate_only': - $messageBags = $repos->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('budgets.create')->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not validate budget: ' . $messages['errors']->first()); } + + // return to create screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('budgets.create')->withInput(); + } + + // store: + $this->_repository->store($data); + Session::flash('success', 'Budget "' . e($data['name']) . '" stored.'); + if ($data['post_submit_action'] == 'store') { + return Redirect::route('budgets.index'); + } + + // create another. + return Redirect::route('budgets.create')->withInput(); } + /** * @param Budget $budget * - * @return $this - * @throws FireflyException + * @return $this|\Illuminate\Http\RedirectResponse */ public function update(Budget $budget) { - /** @var \FireflyIII\Database\Budget $repos */ - $repos = App::make('FireflyIII\Database\Budget'); - $data = Input::except('_token'); + $data = Input::except('_token'); + $data['user_id'] = Auth::user()->id; - switch (Input::get('post_submit_action')) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"'); - break; - case 'return_to_edit': - case 'update': - $messages = $repos->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save budget: ' . $messages['errors']->first()); + // always validate: + $messages = $this->_repository->validate($data); - return Redirect::route('budgets.edit', $budget->id)->withInput()->withErrors($messages['errors']); - } - // store! - $repos->update($budget, $data); - Session::flash('success', 'Budget updated!'); - - if ($data['post_submit_action'] == 'return_to_edit') { - return Redirect::route('budgets.edit', $budget->id); - } else { - return Redirect::route('budgets.index'); - } - case 'validate_only': - $messageBags = $repos->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('budgets.edit', $budget->id)->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not update budget: ' . $messages['errors']->first()); } + + // return to update screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('budgets.edit', $budget->id)->withInput(); + } + + // update + $this->_repository->update($budget, $data); + Session::flash('success', 'Budget "' . e($data['name']) . '" updated.'); + + // go back to list + if ($data['post_submit_action'] == 'update') { + return Redirect::route('budgets.index'); + } + + return Redirect::route('budgets.edit', $budget->id)->withInput(['post_submit_action' => 'return_to_edit']); } /** @@ -297,11 +235,8 @@ class BudgetController extends BaseController */ public function updateIncome() { - $date = Session::get('start'); - /** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */ - $preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface'); - $budgetAmount = $preferences->get('budgetIncomeTotal' . $date->format('FY'), 1000); + $budgetAmount = $this->_preferences->get('budgetIncomeTotal' . Session::get('start', Carbon::now()->startOfMonth())->format('FY'), 1000); - return View::make('budgets.income')->with('amount', $budgetAmount)->with('date', $date); + return View::make('budgets.income')->with('amount', $budgetAmount); } -} \ No newline at end of file +} diff --git a/app/controllers/CategoryController.php b/app/controllers/CategoryController.php index 2093aa54e0..b6d6da5df8 100644 --- a/app/controllers/CategoryController.php +++ b/app/controllers/CategoryController.php @@ -1,19 +1,29 @@ _repository = $repository; } /** @@ -41,11 +51,9 @@ class CategoryController extends BaseController */ public function destroy(Category $category) { - /** @var \FireflyIII\Database\Category $repos */ - $repos = App::make('FireflyIII\Database\Category'); + Session::flash('success', 'Category "' . e($category->name) . '" was deleted.'); + $this->_repository->destroy($category); - $repos->destroy($category); - Session::flash('success', 'The category was deleted.'); return Redirect::route('categories.index'); } @@ -65,9 +73,7 @@ class CategoryController extends BaseController */ public function index() { - /** @var \FireflyIII\Database\Category $repos */ - $repos = App::make('FireflyIII\Database\Category'); - $categories = $repos->get(); + $categories = $this->_repository->get(); return View::make('categories.index', compact('categories')); } @@ -79,12 +85,8 @@ class CategoryController extends BaseController */ public function show(Category $category) { - $hideCategory = true; - - /** @var \FireflyIII\Database\Category $repos */ - $repos = App::make('FireflyIII\Database\Category'); - - $journals = $repos->getTransactionJournals($category, 50); + $hideCategory = true; // used in list. + $journals = $this->_repository->getTransactionJournals($category, 50); return View::make('categories.show', compact('category', 'journals', 'hideCategory')); } @@ -95,44 +97,33 @@ class CategoryController extends BaseController */ public function store() { - $data = Input::all(); - /** @var \FireflyIII\Database\Category $repos */ - $repos = App::make('FireflyIII\Database\Category'); + $data = Input::except('_token'); + $data['user_id'] = Auth::user()->id; - switch ($data['post_submit_action']) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"'); - break; - case 'create_another': - case 'store': - $messages = $repos->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save category: ' . $messages['errors']->first()); + // always validate: + $messages = $this->_repository->validate($data); - return Redirect::route('categories.create')->withInput()->withErrors($messages['errors']); - } - // store! - $repos->store($data); - Session::flash('success', 'New category stored!'); - - if ($data['post_submit_action'] == 'create_another') { - return Redirect::route('categories.create')->withInput(); - } else { - return Redirect::route('categories.index'); - } - break; - case 'validate_only': - $messageBags = $repos->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('categories.create')->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not store category: ' . $messages['errors']->first()); } + + // return to create screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('categories.create')->withInput(); + } + + // store: + $this->_repository->store($data); + Session::flash('success', 'Category "' . e($data['name']) . '" stored.'); + if ($data['post_submit_action'] == 'store') { + return Redirect::route('categories.index'); + } + + return Redirect::route('categories.create')->withInput(); } /** @@ -143,44 +134,37 @@ class CategoryController extends BaseController */ public function update(Category $category) { - /** @var \FireflyIII\Database\Category $repos */ - $repos = App::make('FireflyIII\Database\Category'); - $data = Input::except('_token'); + $data = Input::except('_token'); + $data['user_id'] = Auth::user()->id; - switch (Input::get('post_submit_action')) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"'); - break; - case 'return_to_edit': - case 'update': - $messages = $repos->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save category: ' . $messages['errors']->first()); + // always validate: + $messages = $this->_repository->validate($data); - return Redirect::route('categories.edit', $category->id)->withInput()->withErrors($messages['errors']); - } - // store! - $repos->update($category, $data); - Session::flash('success', 'Category updated!'); - - if ($data['post_submit_action'] == 'return_to_edit') { - return Redirect::route('categories.edit', $category->id); - } else { - return Redirect::route('categories.index'); - } - case 'validate_only': - $messageBags = $repos->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('categories.edit', $category->id)->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not update category: ' . $messages['errors']->first()); } + // return to update screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('categories.edit', $category->id)->withInput(); + } + + // update + $this->_repository->update($category, $data); + Session::flash('success', 'Category "' . e($data['name']) . '" updated.'); + + // go back to list + if ($data['post_submit_action'] == 'update') { + return Redirect::route('categories.index'); + } + + // go back to update screen. + return Redirect::route('categories.edit', $category->id)->withInput(['post_submit_action' => 'return_to_edit']); + } diff --git a/app/controllers/CurrencyController.php b/app/controllers/CurrencyController.php new file mode 100644 index 0000000000..bc2ae575ea --- /dev/null +++ b/app/controllers/CurrencyController.php @@ -0,0 +1,179 @@ +_repository = $repository; + + + View::share('title', 'Currencies'); + View::share('mainTitleIcon', 'fa-usd'); + } + + /** + * @return \Illuminate\View\View + */ + public function create() + { + $subTitleIcon = 'fa-plus'; + $subTitle = 'Create a new currency'; + + return View::make('currency.create', compact('subTitleIcon', 'subTitle')); + } + + /** + * @param TransactionCurrency $currency + * + * @return \Illuminate\Http\RedirectResponse + */ + public function defaultCurrency(TransactionCurrency $currency) + { + /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ + $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); + + $currencyPreference = $preferences->get('currencyPreference', 'EUR'); + $currencyPreference->data = $currency->code; + $currencyPreference->save(); + + Session::flash('success', $currency->name.' is now the default currency.'); + Cache::forget('FFCURRENCYSYMBOL'); + Cache::forget('FFCURRENCYCODE'); + + return Redirect::route('currency.index'); + + } + + /** + * @param TransactionCurrency $currency + */ + public function delete(TransactionCurrency $currency) + { + if ($currency->transactionJournals()->count() > 0) { + Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.'); + + return Redirect::route('currency.index'); + } + + + return View::make('currency.delete', compact('currency')); + } + + public function destroy(TransactionCurrency $currency) + { + Session::flash('success', 'Currency "' . e($currency->name) . '" deleted'); + + $this->_repository->destroy($currency); + + return Redirect::route('currency.index'); + } + + /** + * @param TransactionCurrency $currency + * + * @return \Illuminate\View\View + */ + public function edit(TransactionCurrency $currency) + { + $subTitleIcon = 'fa-pencil'; + $subTitle = 'Edit currency "' . e($currency->name) . '"'; + $currency->symbol = htmlentities($currency->symbol); + + return View::make('currency.edit', compact('currency', 'subTitle', 'subTitleIcon')); + + } + + public function index() + { + $currencies = $this->_repository->get(); + + /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ + $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); + + $currencyPreference = $preferences->get('currencyPreference', 'EUR'); + $defaultCurrency = $this->_repository->findByCode($currencyPreference->data); + + + return View::make('currency.index', compact('currencies', 'defaultCurrency')); + } + + public function store() + { + $data = Input::except('_token'); + + // always validate: + $messages = $this->_repository->validate($data); + + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not store currency: ' . $messages['errors']->first()); + } + + // return to create screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('currency.create')->withInput(); + } + + // store: + $this->_repository->store($data); + Session::flash('success', 'Currency "' . e($data['name']) . '" stored.'); + if ($data['post_submit_action'] == 'store') { + return Redirect::route('currency.index'); + } + + return Redirect::route('currency.create')->withInput(); + + } + + public function update(TransactionCurrency $currency) + { + $data = Input::except('_token'); + + // always validate: + $messages = $this->_repository->validate($data); + + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not update currency: ' . $messages['errors']->first()); + } + + // return to update screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('currency.edit', $currency->id)->withInput(); + } + + // update + $this->_repository->update($currency, $data); + Session::flash('success', 'Currency "' . e($data['name']) . '" updated.'); + + // go back to list + if ($data['post_submit_action'] == 'update') { + return Redirect::route('currency.index'); + } + + return Redirect::route('currency.edit', $currency->id)->withInput(['post_submit_action' => 'return_to_edit']); + + } + +} \ No newline at end of file diff --git a/app/controllers/GoogleChartController.php b/app/controllers/GoogleChartController.php index 0eb2b58396..2a5786c5f6 100644 --- a/app/controllers/GoogleChartController.php +++ b/app/controllers/GoogleChartController.php @@ -1,12 +1,41 @@ _chart = $chart; + $this->_repository = $repository; + $this->_start = Session::get('start', Carbon::now()->startOfMonth()); + $this->_end = Session::get('end', Carbon::now()->endOfMonth()); + + } + /** * @param Account $account * @param string $view @@ -15,199 +44,37 @@ class GoogleChartController extends BaseController */ public function accountBalanceChart(Account $account, $view = 'session') { - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); + $this->_chart->addColumn('Day of month', 'date'); + $this->_chart->addColumn('Balance for ' . $account->name, 'number'); - $chart->addColumn('Day of month', 'date'); - $chart->addColumn('Balance for ' . $account->name, 'number'); + // TODO this can be combined in some method, it's coming up quite often, is it? + $start = $this->_start; + $end = $this->_end; + $count = $account->transactions()->count(); - /* - * Loop the date, then loop the accounts, then add balance. - */ - switch ($view) { - default: - case 'session': - $start = Session::get('start'); - $end = Session::get('end'); - break; - case 'all': - $first = $account->transactionjournals()->orderBy('date', 'DESC')->first(); - $last = $account->transactionjournals()->orderBy('date', 'ASC')->first(); - if (is_null($first)) { - $start = Session::get('start'); - } else { - $start = clone $first->date; - } - if (is_null($last)) { - $end = Session::get('end'); - } else { - $end = clone $last->date; - } - break; + if ($view == 'all' && $count > 0) { + $first = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy( + 'date', 'ASC' + )->first(['transaction_journals.date']); + $last = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy( + 'date', 'DESC' + )->first(['transaction_journals.date']); + $start = new Carbon($first->date); + $end = new Carbon($last->date); } + // todo until this part. $current = clone $start; while ($end >= $current) { - $row = [clone $current]; - if ($current > Carbon::now()) { - $row[] = null; - } else { - $row[] = Steam::balance($account, $current); - } - - $chart->addRowArray($row); + $this->_chart->addRow(clone $current, Steam::balance($account, $current)); $current->addDay(); } - $chart->generate(); - - return Response::json($chart->getData()); - } - - /** - * @param Account $account - * @param string $view - * - * @return \Illuminate\Http\JsonResponse - */ - public function accountSankeyInChart(Account $account, $view = 'session') - { - // collect all relevant entries. - $set = []; - - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('From', 'string'); - $chart->addColumn('To', 'string', 'domain'); - $chart->addColumn('Weight', 'number'); - - switch ($view) { - default: - case 'session': - $start = Session::get('start'); - $end = Session::get('end'); - break; - case 'all': - $first = $account->transactionjournals()->orderBy('date', 'DESC')->first(); - $last = $account->transactionjournals()->orderBy('date', 'ASC')->first(); - if (is_null($first)) { - $start = Session::get('start'); - } else { - $start = clone $first->date; - } - if (is_null($last)) { - $end = Session::get('end'); - } else { - $end = clone $last->date; - } - break; - } - - - $transactions = $account->transactions()->with( - ['transactionjournal', 'transactionjournal.transactions' => function ($q) { - $q->where('amount', '<', 0); - }, 'transactionjournal.budgets', 'transactionjournal.transactiontype', 'transactionjournal.categories'] - )->before($end)->after($start)->get(); - - /** @var Transaction $transaction */ - foreach ($transactions as $transaction) { - $amount = floatval($transaction->amount); - $type = $transaction->transactionJournal->transactionType->type; - - if ($amount > 0 && $type != 'Transfer') { - - $otherAccount = $transaction->transactionJournal->transactions[0]->account->name; - $categoryName = isset($transaction->transactionJournal->categories[0]) ? $transaction->transactionJournal->categories[0]->name : '(no cat)'; - $set[] = [$otherAccount, $categoryName, $amount]; - $set[] = [$categoryName, $account->name, $amount]; - } - } - // loop the set, group everything together: - $grouped = []; - foreach ($set as $entry) { - $key = $entry[0] . $entry[1]; - if (isset($grouped[$key])) { - $grouped[$key][2] += $entry[2]; - } else { - $grouped[$key] = $entry; - } - } - - // add rows to the chart: - foreach ($grouped as $entry) { - $chart->addRow($entry[0], $entry[1], $entry[2]); - } - - $chart->generate(); - - return Response::json($chart->getData()); - - } - - /** - * @param Account $account - * @param string $view - * - * @return \Illuminate\Http\JsonResponse - */ - public function accountSankeyOutChart(Account $account, $view = 'session') - { - // collect all relevant entries. - $set = []; - - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('From', 'string'); - $chart->addColumn('To', 'string', 'domain'); - $chart->addColumn('Weight', 'number'); - - $transactions = $account->transactions()->with( - ['transactionjournal', 'transactionjournal.transactions', 'transactionjournal.budgets', 'transactionjournal.transactiontype', - 'transactionjournal.categories'] - )->before(Session::get('end'))->after( - Session::get('start') - )->get(); - - /** @var Transaction $transaction */ - foreach ($transactions as $transaction) { - $amount = floatval($transaction->amount); - $type = $transaction->transactionJournal->transactionType->type; - - if ($amount < 0 && $type != 'Transfer') { - - // from account to a budget (if present). - $budgetName = isset($transaction->transactionJournal->budgets[0]) ? $transaction->transactionJournal->budgets[0]->name : '(no budget)'; - $set[] = [$account->name, $budgetName, $amount * -1]; - - // from budget to category. - $categoryName = isset($transaction->transactionJournal->categories[0]) ? ' ' . $transaction->transactionJournal->categories[0]->name - : '(no cat)'; - $set[] = [$budgetName, $categoryName, $amount * -1]; - } - } - // loop the set, group everything together: - $grouped = []; - foreach ($set as $entry) { - $key = $entry[0] . $entry[1]; - if (isset($grouped[$key])) { - $grouped[$key][2] += $entry[2]; - } else { - $grouped[$key] = $entry; - } - } - - // add rows to the chart: - foreach ($grouped as $entry) { - $chart->addRow($entry[0], $entry[1], $entry[2]); - } - - $chart->generate(); - - return Response::json($chart->getData()); + $this->_chart->generate(); + return Response::json($this->_chart->getData()); } /** @@ -215,51 +82,34 @@ class GoogleChartController extends BaseController */ public function allAccountsBalanceChart() { - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Day of the month', 'date'); + $this->_chart->addColumn('Day of the month', 'date'); /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); $pref = $preferences->get('frontpageAccounts', []); - /** @var \FireflyIII\Database\Account $acct */ - $acct = App::make('FireflyIII\Database\Account'); - if (count($pref->data) > 0) { - $accounts = $acct->getByIds($pref->data); - } else { - $accounts = $acct->getAssetAccounts(); - } + /** @var \FireflyIII\Database\Account\Account $acct */ + $acct = App::make('FireflyIII\Database\Account\Account'); + $accounts = count($pref->data) > 0 ? $acct->getByIds($pref->data) : $acct->getAssetAccounts(); - - /* - * Add a column for each account. - */ /** @var Account $account */ foreach ($accounts as $account) { - $chart->addColumn('Balance for ' . $account->name, 'number'); + $this->_chart->addColumn('Balance for ' . $account->name, 'number'); } - /* - * Loop the date, then loop the accounts, then add balance. - */ - $start = Session::get('start'); - $end = Session::get('end'); - $current = clone $start; + $current = clone $this->_start; - while ($end >= $current) { + while ($this->_end >= $current) { $row = [clone $current]; - foreach ($accounts as $account) { $row[] = Steam::balance($account, $current); } - - $chart->addRowArray($row); + $this->_chart->addRowArray($row); $current->addDay(); } - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } @@ -268,68 +118,49 @@ class GoogleChartController extends BaseController */ public function allBudgetsHomeChart() { - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Budget', 'string'); - $chart->addColumn('Budgeted', 'number'); - $chart->addColumn('Spent', 'number'); + $this->_chart->addColumn('Budget', 'string'); + $this->_chart->addColumn('Budgeted', 'number'); + $this->_chart->addColumn('Spent', 'number'); - /** @var \FireflyIII\Database\Budget $bdt */ - $bdt = App::make('FireflyIII\Database\Budget'); + Log::debug('Now in allBudgetsHomeChart()'); + + /** @var \FireflyIII\Database\Budget\Budget $bdt */ + $bdt = App::make('FireflyIII\Database\Budget\Budget'); $budgets = $bdt->get(); - /* - * Loop budgets: - */ /** @var Budget $budget */ foreach ($budgets as $budget) { - /* - * Is there a repetition starting on this particular date? We can use that. - */ + Log::debug('Now working budget #'.$budget->id.', '.$budget->name); + /** @var \LimitRepetition $repetition */ - $repetition = $bdt->repetitionOnStartingOnDate($budget, Session::get('start')); - - /* - * If there is, use it. Otherwise, forget it. - */ + $repetition = $bdt->repetitionOnStartingOnDate($budget, $this->_start); if (is_null($repetition)) { + \Log::debug('Budget #'.$budget->id.' has no repetition on ' . $this->_start->format('Y-m-d')); // use the session start and end for our search query - $searchStart = Session::get('start'); - $searchEnd = Session::get('end'); - // the limit is zero: - $limit = 0; - + $searchStart = $this->_start; + $searchEnd = $this->_end; + $limit = 0; // the limit is zero: } else { + \Log::debug('Budget #'.$budget->id.' has a repetition on ' . $this->_start->format('Y-m-d').'!'); // use the limit's start and end for our search query $searchStart = $repetition->startdate; $searchEnd = $repetition->enddate; - // the limit is the repetitions limit: - $limit = floatval($repetition->amount); + $limit = floatval($repetition->amount); // the limit is the repetitions limit: } - /* - * No matter the result of the search for the repetition, get all the transactions associated - * with the budget, and sum up the expenses made. - */ $expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1; if ($expenses > 0) { - $chart->addRow($budget->name, $limit, $expenses); + $this->_chart->addRow($budget->name, $limit, $expenses); } } - /* - * Finally, get all transactions WITHOUT a budget and add those as well. - * (yes this method is oddly specific). - */ - $noBudgetSet = $bdt->transactionsWithoutBudgetInDateRange(Session::get('start'), Session::get('end')); + $noBudgetSet = $bdt->transactionsWithoutBudgetInDateRange($this->_start, $this->_end); $sum = $noBudgetSet->sum('amount') * -1; - $chart->addRow('No budget', 0, $sum); + $this->_chart->addRow('No budget', 0, $sum); + $this->_chart->generate(); - - $chart->generate(); - - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } /** @@ -337,48 +168,26 @@ class GoogleChartController extends BaseController */ public function allCategoriesHomeChart() { - $data = []; + $this->_chart->addColumn('Category', 'string'); + $this->_chart->addColumn('Spent', 'number'); - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Category', 'string'); - $chart->addColumn('Spent', 'number'); + // query! + $set = $this->_repository->getCategorySummary($this->_start, $this->_end); - /** @var \FireflyIII\Database\TransactionJournal $tj */ - $tj = App::make('FireflyIII\Database\TransactionJournal'); - - /* - * Get the journals: - */ - $journals = $tj->getInDateRange(Session::get('start'), Session::get('end')); - - /** @var \TransactionJournal $journal */ - foreach ($journals as $journal) { - if ($journal->transactionType->type == 'Withdrawal') { - $amount = $journal->getAmount(); - $category = $journal->categories()->first(); - if (!is_null($category)) { - if (isset($data[$category->name])) { - $data[$category->name] += $amount; - } else { - $data[$category->name] = $amount; - } - } - } - } - arsort($data); - foreach ($data as $key => $entry) { - $chart->addRow($key, $entry); + foreach ($set as $entry) { + $entry->name = strlen($entry->name) == 0 ? '(no category)' : $entry->name; + $this->_chart->addRow($entry->name, floatval($entry->sum)); } + $this->_chart->generate(); - $chart->generate(); - - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } /** + * TODO still in use? + * * @param Budget $budget * @param LimitRepetition $repetition * @@ -389,10 +198,8 @@ class GoogleChartController extends BaseController $start = clone $repetition->startdate; $end = $repetition->enddate; - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Day', 'date'); - $chart->addColumn('Left', 'number'); + $this->_chart->addColumn('Day', 'date'); + $this->_chart->addColumn('Left', 'number'); $amount = $repetition->amount; @@ -403,105 +210,42 @@ class GoogleChartController extends BaseController */ $sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount')); $amount += $sum; - $chart->addRow(clone $start, $amount); + $this->_chart->addRow(clone $start, $amount); $start->addDay(); } - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } /** - * @param $year + * TODO still in use? * - * @return \Illuminate\Http\JsonResponse - */ - public function budgetsReportChart($year) - { - - try { - $start = new Carbon('01-01-' . $year); - } catch (Exception $e) { - App::abort(500); - } - - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - - /** @var \FireflyIII\Database\Budget $bdt */ - $bdt = App::make('FireflyIII\Database\Budget'); - $budgets = $bdt->get(); - - $chart->addColumn('Month', 'date'); - /** @var \Budget $budget */ - foreach ($budgets as $budget) { - $chart->addColumn($budget->name, 'number'); - } - $chart->addColumn('No budget', 'number'); - - /* - * Loop budgets this year. - */ - $end = clone $start; - $end->endOfYear(); - while ($start <= $end) { - $row = [clone $start]; - - foreach ($budgets as $budget) { - $row[] = $bdt->spentInMonth($budget, $start); - } - - /* - * Without a budget: - */ - $endOfMonth = clone $start; - $endOfMonth->endOfMonth(); - $set = $bdt->transactionsWithoutBudgetInDateRange($start, $endOfMonth); - $row[] = floatval($set->sum('amount')) * -1; - - $chart->addRowArray($row); - $start->addMonth(); - } - - - $chart->generate(); - - return Response::json($chart->getData()); - } - - /** - * @param Component $component + * @param Budget $component * @param $year * * @return \Illuminate\Http\JsonResponse */ - public function componentsAndSpending(Component $component, $year) + public function budgetsAndSpending(Budget $component, $year) { try { - $start = new Carbon('01-01-' . $year); + new Carbon('01-01-' . $year); } catch (Exception $e) { - App::abort(500); + return View::make('error')->with('message', 'Invalid year.'); } - if ($component->class == 'Budget') { - /** @var \FireflyIII\Database\Budget $repos */ - $repos = App::make('FireflyIII\Database\Budget'); - } else { - /** @var \FireflyIII\Database\Category $repos */ - $repos = App::make('FireflyIII\Database\Category'); - } + /** @var \FireflyIII\Database\Budget\Budget $repos */ + $repos = App::make('FireflyIII\Database\Budget\Budget'); - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Month', 'date'); - $chart->addColumn('Budgeted', 'number'); - $chart->addColumn('Spent', 'number'); + $this->_chart->addColumn('Month', 'date'); + $this->_chart->addColumn('Budgeted', 'number'); + $this->_chart->addColumn('Spent', 'number'); - $end = clone $start; + $start = new Carbon('01-01-' . $year); + $end = clone $start; $end->endOfYear(); while ($start <= $end) { - $spent = $repos->spentInMonth($component, $start); $repetition = $repos->repetitionOnStartingOnDate($component, $start); if ($repetition) { @@ -510,15 +254,59 @@ class GoogleChartController extends BaseController $budgeted = null; } - $chart->addRow(clone $start, $budgeted, $spent); + $this->_chart->addRow(clone $start, $budgeted, $spent); $start->addMonth(); } - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); + + + } + + /** + * TODO still in use? + * + * @param Category $component + * @param $year + * + * @return \Illuminate\Http\JsonResponse + */ + public function categoriesAndSpending(Category $component, $year) + { + try { + new Carbon('01-01-' . $year); + } catch (Exception $e) { + return View::make('error')->with('message', 'Invalid year.'); + } + + /** @var \FireflyIII\Database\Category\Category $repos */ + $repos = App::make('FireflyIII\Database\Category\Category'); + + $this->_chart->addColumn('Month', 'date'); + $this->_chart->addColumn('Budgeted', 'number'); + $this->_chart->addColumn('Spent', 'number'); + + $start = new Carbon('01-01-' . $year); + $end = clone $start; + $end->endOfYear(); + while ($start <= $end) { + + $spent = $repos->spentInMonth($component, $start); + $budgeted = null; + + $this->_chart->addRow(clone $start, $budgeted, $spent); + + $start->addMonth(); + } + + + $this->_chart->generate(); + + return Response::json($this->_chart->getData()); } @@ -530,20 +318,18 @@ class GoogleChartController extends BaseController */ public function piggyBankHistory(\Piggybank $piggybank) { - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Date', 'date'); - $chart->addColumn('Balance', 'number'); + $this->_chart->addColumn('Date', 'date'); + $this->_chart->addColumn('Balance', 'number'); - $set = \DB::table('piggybank_events')->where('piggybank_id', $piggybank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]); + $set = \DB::table('piggy_bank_events')->where('piggybank_id', $piggybank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]); foreach ($set as $entry) { - $chart->addRow(new Carbon($entry->date), floatval($entry->sum)); + $this->_chart->addRow(new Carbon($entry->date), floatval($entry->sum)); } - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } @@ -555,12 +341,10 @@ class GoogleChartController extends BaseController public function recurringOverview(RecurringTransaction $recurring) { - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Date', 'date'); - $chart->addColumn('Max amount', 'number'); - $chart->addColumn('Min amount', 'number'); - $chart->addColumn('Current entry', 'number'); + $this->_chart->addColumn('Date', 'date'); + $this->_chart->addColumn('Max amount', 'number'); + $this->_chart->addColumn('Min amount', 'number'); + $this->_chart->addColumn('Current entry', 'number'); // get first transaction or today for start: $first = $recurring->transactionjournals()->orderBy('date', 'ASC')->first(); @@ -578,98 +362,50 @@ class GoogleChartController extends BaseController $amount = 0; } unset($result); - $chart->addRow(clone $start, $recurring->amount_max, $recurring->amount_min, $amount); + $this->_chart->addRow(clone $start, $recurring->amount_max, $recurring->amount_min, $amount); $start = DateKit::addPeriod($start, $recurring->repeat_freq, 0); } - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } /** + * TODO query move to helper. + * * @return \Illuminate\Http\JsonResponse * @throws \FireflyIII\Exception\FireflyException */ public function recurringTransactionsOverview() { - - /* - * Set of paid transaction journals. - * Set of unpaid recurring transactions. - */ $paid = ['items' => [], 'amount' => 0]; $unpaid = ['items' => [], 'amount' => 0]; + $this->_chart->addColumn('Name', 'string'); + $this->_chart->addColumn('Amount', 'number'); - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Name', 'string'); - $chart->addColumn('Amount', 'number'); - - /** @var \FireflyIII\Database\Recurring $rcr */ - $rcr = App::make('FireflyIII\Database\Recurring'); - - $recurring = $rcr->get(); - - /** @var \RecurringTransaction $entry */ - foreach ($recurring as $entry) { - /* - * Start another loop starting at the $date. - */ - $start = clone $entry->date; - $end = Carbon::now(); - - /* - * The jump we make depends on the $repeat_freq - */ - $current = clone $start; - - while ($current <= $end) { - /* - * Get end of period for $current: - */ - $currentEnd = DateKit::endOfPeriod($current, $entry->repeat_freq); - - /* - * In the current session range? - */ - if (\Session::get('end') >= $current and $currentEnd >= \Session::get('start')) { - /* - * Lets see if we've already spent money on this recurring transaction (it hath recurred). - */ - /** @var TransactionJournal $set */ - $journal = $rcr->getJournalForRecurringInRange($entry, $current, $currentEnd); - - if (is_null($journal)) { - $unpaid['items'][] = $entry->name; - $unpaid['amount'] += (($entry->amount_max + $entry->amount_min) / 2); - } else { - $amount = $journal->getAmount(); - $paid['items'][] = $journal->description; - $paid['amount'] += $amount; - } - } - - /* - * Add some time for the next loop! - */ - $current = DateKit::addPeriod($current, $entry->repeat_freq, intval($entry->skip)); + $set = $this->_repository->getRecurringSummary($this->_start, $this->_end); + foreach ($set as $entry) { + if (intval($entry->journalId) == 0) { + $unpaid['items'][] = $entry->name; + $unpaid['amount'] += floatval($entry->averageAmount); + } else { + $paid['items'][] = $entry->description; + $paid['amount'] += floatval($entry->actualAmount); } - } - /** @var \RecurringTransaction $entry */ - $chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']); - $chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']); - - $chart->generate(); - - return Response::json($chart->getData()); + $this->_chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']); + $this->_chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']); + $this->_chart->generate(); + return Response::json($this->_chart->getData()); } /** + * TODO see reports for better way to do this. + * * @param $year * * @return \Illuminate\Http\JsonResponse @@ -679,37 +415,37 @@ class GoogleChartController extends BaseController try { $start = new Carbon('01-01-' . $year); } catch (Exception $e) { - App::abort(500); + return View::make('error')->with('message', 'Invalid year.'); } - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Month', 'date'); - $chart->addColumn('Income', 'number'); - $chart->addColumn('Expenses', 'number'); + $this->_chart->addColumn('Month', 'date'); + $this->_chart->addColumn('Income', 'number'); + $this->_chart->addColumn('Expenses', 'number'); - /** @var \FireflyIII\Database\TransactionJournal $tj */ - $tj = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $end = clone $start; $end->endOfYear(); while ($start < $end) { // total income: - $income = $tj->getSumOfIncomesByMonth($start); - $expense = $tj->getSumOfExpensesByMonth($start); + $income = $repository->getSumOfIncomesByMonth($start); + $expense = $repository->getSumOfExpensesByMonth($start); - $chart->addRow(clone $start, $income, $expense); + $this->_chart->addRow(clone $start, $income, $expense); $start->addMonth(); } - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } /** + * TODO see reports for better way to do this. + * * @param $year * * @return \Illuminate\Http\JsonResponse @@ -719,16 +455,14 @@ class GoogleChartController extends BaseController try { $start = new Carbon('01-01-' . $year); } catch (Exception $e) { - App::abort(500); + return View::make('error')->with('message', 'Invalid year.'); } - /** @var \Grumpydictator\Gchart\GChart $chart */ - $chart = App::make('gchart'); - $chart->addColumn('Summary', 'string'); - $chart->addColumn('Income', 'number'); - $chart->addColumn('Expenses', 'number'); + $this->_chart->addColumn('Summary', 'string'); + $this->_chart->addColumn('Income', 'number'); + $this->_chart->addColumn('Expenses', 'number'); - /** @var \FireflyIII\Database\TransactionJournal $tj */ - $tj = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $end = clone $start; $end->endOfYear(); @@ -738,20 +472,20 @@ class GoogleChartController extends BaseController while ($start < $end) { // total income: - $income += $tj->getSumOfIncomesByMonth($start); - $expense += $tj->getSumOfExpensesByMonth($start); + $income += $repository->getSumOfIncomesByMonth($start); + $expense += $repository->getSumOfExpensesByMonth($start); $count++; $start->addMonth(); } - $chart->addRow('Sum', $income, $expense); + $this->_chart->addRow('Sum', $income, $expense); $count = $count > 0 ? $count : 1; - $chart->addRow('Average', ($income / $count), ($expense / $count)); + $this->_chart->addRow('Average', ($income / $count), ($expense / $count)); - $chart->generate(); + $this->_chart->generate(); - return Response::json($chart->getData()); + return Response::json($this->_chart->getData()); } } \ No newline at end of file diff --git a/app/controllers/HelpController.php b/app/controllers/HelpController.php index 1424351c40..ee5f57fbfc 100644 --- a/app/controllers/HelpController.php +++ b/app/controllers/HelpController.php @@ -12,11 +12,9 @@ class HelpController extends BaseController */ public function show($route) { - // no valid route + $helpText = '

There is no help for this route!

'; + $helpTitle = 'Help'; if (!Route::has($route)) { - $helpText = '

There is no help for this route!

'; - $helpTitle = 'Help'; - return Response::json(['title' => $helpTitle, 'text' => $helpText]); } @@ -28,25 +26,17 @@ class HelpController extends BaseController return Response::json(['title' => $helpTitle, 'text' => $helpText]); } - // get the help-content from Github: - $URL = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md'; + $uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md'; try { - $content = file_get_contents($URL); + $content = file_get_contents($uri); } catch (ErrorException $e) { $content = '

There is no help for this route.

'; } - if (strlen($content) > 0) { - $helpText = \Michelf\Markdown::defaultTransform($content); - $helpTitle = $route; + $helpText = \Michelf\Markdown::defaultTransform($content); + $helpTitle = $route; - Cache::put('help.' . $route . '.text', $helpText, 10080); // a week. - Cache::put('help.' . $route . '.title', $helpTitle, 10080); - - return Response::json(['title' => $helpTitle, 'text' => $helpText]); - } - - $helpText = '

There is no help for this route!

'; - $helpTitle = 'Help'; + Cache::put('help.' . $route . '.text', $helpText, 10080); // a week. + Cache::put('help.' . $route . '.title', $helpTitle, 10080); return Response::json(['title' => $helpTitle, 'text' => $helpText]); diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php index 9617608efc..faea3a7f68 100644 --- a/app/controllers/HomeController.php +++ b/app/controllers/HomeController.php @@ -1,4 +1,5 @@ countAssetAccounts(); - $start = Session::get('start'); - $end = Session::get('end'); + $start = Session::get('start', Carbon::now()->startOfMonth()); + $end = Session::get('end', Carbon::now()->endOfMonth()); // get the preference for the home accounts to show: @@ -47,7 +48,7 @@ class HomeController extends BaseController $transactions = []; foreach ($accounts as $account) { - $set = $jrnls->getInDateRangeAccount($account, 10, $start, $end); + $set = $jrnls->getInDateRangeAccount($account, $start, $end, 10); if (count($set) > 0) { $transactions[] = [$set, $account]; } @@ -76,7 +77,7 @@ class HomeController extends BaseController Session::forget('range'); } - return Redirect::back(); + return Redirect::intended('/'); } /** @@ -86,7 +87,7 @@ class HomeController extends BaseController { Navigation::next(); - return Redirect::back(); + return Redirect::intended('/'); } /** @@ -96,6 +97,6 @@ class HomeController extends BaseController { Navigation::prev(); - return Redirect::back(); + return Redirect::intended('/'); } } \ No newline at end of file diff --git a/app/controllers/JsonController.php b/app/controllers/JsonController.php index 9f0512572a..094a3fc040 100644 --- a/app/controllers/JsonController.php +++ b/app/controllers/JsonController.php @@ -14,8 +14,8 @@ class JsonController extends BaseController */ public function categories() { - /** @var \FireflyIII\Database\Category $categories */ - $categories = App::make('FireflyIII\Database\Category'); + /** @var \FireflyIII\Database\Category\Category $categories */ + $categories = App::make('FireflyIII\Database\Category\Category'); $list = $categories->get(); $return = []; foreach ($list as $entry) { @@ -34,8 +34,8 @@ class JsonController extends BaseController */ public function expenseAccounts() { - /** @var \FireflyIII\Database\Account $accounts */ - $accounts = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $accounts */ + $accounts = App::make('FireflyIII\Database\Account\Account'); $list = $accounts->getExpenseAccounts(); $return = []; foreach ($list as $entry) { @@ -51,8 +51,8 @@ class JsonController extends BaseController */ public function revenueAccounts() { - /** @var \FireflyIII\Database\Account $accounts */ - $accounts = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $accounts */ + $accounts = App::make('FireflyIII\Database\Account\Account'); $list = $accounts->getRevenueAccounts(); $return = []; foreach ($list as $entry) { diff --git a/app/controllers/PiggybankController.php b/app/controllers/PiggybankController.php index eb933934af..307197ac32 100644 --- a/app/controllers/PiggybankController.php +++ b/app/controllers/PiggybankController.php @@ -1,21 +1,35 @@ _repository = $repository; + View::share('title', 'Piggy banks'); + View::share('mainTitleIcon', 'fa-sort-amount-asc'); } /** @@ -27,16 +41,23 @@ class PiggybankController extends BaseController */ public function add(Piggybank $piggybank) { - /** @var \FireflyIII\Database\Piggybank $repos */ - $repos = App::make('FireflyIII\Database\Piggybank'); + \Log::debug('Now in add() for piggy bank #' . $piggybank->id . ' (' . $piggybank->name . ')'); + \Log::debug('Z'); + \Log::debug('currentRelevantRep is null: ' . boolstr($piggybank->currentRelevantRep())); + $leftOnAccount = $this->_repository->leftOnAccount($piggybank->account); + \Log::debug('A'); - $leftOnAccount = $repos->leftOnAccount($piggybank->account); - $savedSoFar = $piggybank->currentRelevantRep()->currentamount; - $leftToSave = $piggybank->targetamount - $savedSoFar; - $amount = min($leftOnAccount, $leftToSave); + $savedSoFar = $piggybank->currentRelevantRep()->currentamount; + \Log::debug('B'); + $leftToSave = $piggybank->targetamount - $savedSoFar; + \Log::debug('C'); + $maxAmount = min($leftOnAccount, $leftToSave); + \Log::debug('D'); - return View::make('piggybanks.add', compact('piggybank'))->with('maxAmount', $amount); + \Log::debug('Now going to view for piggy bank #' . $piggybank->id . ' (' . $piggybank->name . ')'); + + return View::make('piggybanks.add', compact('piggybank', 'maxAmount')); } /** @@ -45,17 +66,15 @@ class PiggybankController extends BaseController public function create() { - /** @var \FireflyIII\Database\Account $acct */ - $acct = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $acct */ + $acct = App::make('FireflyIII\Database\Account\Account'); - $periods = Config::get('firefly.piggybank_periods'); + $periods = Config::get('firefly.piggybank_periods'); + $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $subTitle = 'Create new piggy bank'; + $subTitleIcon = 'fa-plus'; - - $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); - - return View::make('piggybanks.create', compact('accounts', 'periods'))->with('title', 'Piggy banks')->with('mainTitleIcon', 'fa-sort-amount-asc')->with( - 'subTitle', 'Create new piggy bank' - )->with('subTitleIcon', 'fa-plus'); + return View::make('piggybanks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon')); } /** @@ -65,9 +84,9 @@ class PiggybankController extends BaseController */ public function delete(Piggybank $piggybank) { - return View::make('piggybanks.delete')->with('piggybank', $piggybank)->with('subTitle', 'Delete "' . $piggybank->name . '"')->with( - 'title', 'Piggy banks' - )->with('mainTitleIcon', 'fa-sort-amount-asc'); + $subTitle = 'Delete "' . e($piggybank->name) . '"'; + + return View::make('piggybanks.delete', compact('piggybank', 'subTitle')); } /** @@ -77,10 +96,9 @@ class PiggybankController extends BaseController */ public function destroy(Piggybank $piggyBank) { - /** @var \FireflyIII\Database\Piggybank $acct */ - $repos = App::make('FireflyIII\Database\Piggybank'); - $repos->destroy($piggyBank); - Session::flash('success', 'Piggy bank deleted.'); + + Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.'); + $this->_repository->destroy($piggyBank); return Redirect::route('piggybanks.index'); } @@ -93,28 +111,33 @@ class PiggybankController extends BaseController public function edit(Piggybank $piggybank) { - /** @var \FireflyIII\Database\Account $acct */ - $acct = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $acct */ + $acct = App::make('FireflyIII\Database\Account\Account'); - $periods = Config::get('firefly.piggybank_periods'); - - $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $periods = Config::get('firefly.piggybank_periods'); + $accounts = FFForm::makeSelectList($acct->getAssetAccounts()); + $subTitle = 'Edit piggy bank "' . e($piggybank->name) . '"'; + $subTitleIcon = 'fa-pencil'; /* * Flash some data to fill the form. */ + if (is_null($piggybank->targetdate) || $piggybank->targetdate == '') { + $targetDate = null; + } else { + $targetDate = new Carbon($piggybank->targetdate); + $targetDate = $targetDate->format('Y-m-d'); + } $preFilled = ['name' => $piggybank->name, 'account_id' => $piggybank->account_id, 'targetamount' => $piggybank->targetamount, - 'targetdate' => !is_null($piggybank->targetdate) ? $piggybank->targetdate->format('Y-m-d') : null, + 'targetdate' => $targetDate, 'reminder' => $piggybank->reminder, 'remind_me' => intval($piggybank->remind_me) == 1 || !is_null($piggybank->reminder) ? true : false ]; Session::flash('preFilled', $preFilled); - return View::make('piggybanks.edit', compact('piggybank', 'accounts', 'periods', 'preFilled'))->with('title', 'Piggybanks')->with( - 'mainTitleIcon', 'fa-sort-amount-asc' - )->with('subTitle', 'Edit piggy bank "' . e($piggybank->name) . '"')->with('subTitleIcon', 'fa-pencil'); + return View::make('piggybanks.edit', compact('subTitle', 'subTitleIcon', 'piggybank', 'accounts', 'periods', 'preFilled')); } /** @@ -122,11 +145,8 @@ class PiggybankController extends BaseController */ public function index() { - /** @var \FireflyIII\Database\Piggybank $repos */ - $repos = App::make('FireflyIII\Database\Piggybank'); - /** @var Collection $piggybanks */ - $piggybanks = $repos->get(); + $piggybanks = $this->_repository->get(); $accounts = []; /** @var Piggybank $piggybank */ @@ -140,9 +160,14 @@ class PiggybankController extends BaseController */ $account = $piggybank->account; if (!isset($accounts[$account->id])) { - $accounts[$account->id] = ['name' => $account->name, 'balance' => Steam::balance($account), - 'leftForPiggybanks' => $repos->leftOnAccount($account), 'sumOfSaved' => $piggybank->savedSoFar, - 'sumOfTargets' => floatval($piggybank->targetamount), 'leftToSave' => $piggybank->leftToSave]; + $accounts[$account->id] = [ + 'name' => $account->name, + 'balance' => Steam::balance($account), + 'leftForPiggybanks' => $this->_repository->leftOnAccount($account), + 'sumOfSaved' => $piggybank->savedSoFar, + 'sumOfTargets' => floatval($piggybank->targetamount), + 'leftToSave' => $piggybank->leftToSave + ]; } else { $accounts[$account->id]['sumOfSaved'] += $piggybank->savedSoFar; $accounts[$account->id]['sumOfTargets'] += floatval($piggybank->targetamount); @@ -150,7 +175,7 @@ class PiggybankController extends BaseController } } - return View::make('piggybanks.index', compact('piggybanks', 'accounts'))->with('title', 'Piggy banks')->with('mainTitleIcon', 'fa-sort-amount-asc'); + return View::make('piggybanks.index', compact('piggybanks', 'accounts')); } /** @@ -164,8 +189,8 @@ class PiggybankController extends BaseController { $amount = round(floatval(Input::get('amount')), 2); - /** @var \FireflyIII\Database\Piggybank $acct */ - $repos = App::make('FireflyIII\Database\Piggybank'); + /** @var \FireflyIII\Database\PiggyBank\PiggyBank $acct */ + $repos = App::make('FireflyIII\Database\PiggyBank\PiggyBank'); $leftOnAccount = $repos->leftOnAccount($piggybank->account); $savedSoFar = $piggybank->currentRelevantRep()->currentamount; @@ -226,7 +251,7 @@ class PiggybankController extends BaseController */ public function remove(Piggybank $piggybank) { - return View::make('piggybanks.remove', compact('piggybank')); + return View::make('piggybanks.remove')->with('piggybank', $piggybank); } /** @@ -245,12 +270,9 @@ class PiggybankController extends BaseController $amountPerReminder = $piggybank->amountPerReminder(); $remindersCount = $piggybank->countFutureReminders(); + $subTitle = e($piggybank->name); - return View::make('piggybanks.show', compact('amountPerReminder', 'remindersCount', 'piggybank', 'events'))->with('title', 'Piggy banks')->with( - 'mainTitleIcon', 'fa-sort-amount-asc' - )->with( - 'subTitle', $piggybank->name - ); + return View::make('piggybanks.show', compact('amountPerReminder', 'remindersCount', 'piggybank', 'events', 'subTitle')); } @@ -261,49 +283,35 @@ class PiggybankController extends BaseController { $data = Input::all(); $data['repeats'] = 0; - /** @var \FireflyIII\Database\Piggybank $repos */ - $repos = App::make('FireflyIII\Database\Piggybank'); + $data['user_id'] = Auth::user()->id; - switch ($data['post_submit_action']) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"'); - break; - case 'create_another': - case 'store': - $messages = $repos->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save piggy bank: ' . $messages['errors']->first()); - return Redirect::route('piggybanks.create')->withInput()->withErrors($messages['errors']); - } - // store! - $piggyBank = $repos->store($data); + // always validate: + $messages = $this->_repository->validate($data); - /* - * Create the relevant repetition per Event. - */ - Event::fire('piggybank.store', [$piggyBank]); // new and used. - - Session::flash('success', 'New piggy bank stored!'); - - if ($data['post_submit_action'] == 'create_another') { - return Redirect::route('piggybanks.create')->withInput(); - } else { - return Redirect::route('piggybanks.index'); - } - break; - case 'validate_only': - $messageBags = $repos->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('piggybanks.create')->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not store piggy bank: ' . $messages['errors']->first()); } + + + // return to create screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('piggybanks.create')->withInput(); + } + + // store: + $piggyBank = $this->_repository->store($data); + Event::fire('piggybank.store', [$piggyBank]); // new and used. + Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.'); + if ($data['post_submit_action'] == 'store') { + return Redirect::route('piggybanks.index'); + } + + return Redirect::route('piggybanks.create')->withInput(); } /** @@ -315,45 +323,40 @@ class PiggybankController extends BaseController public function update(Piggybank $piggyBank) { - /** @var \FireflyIII\Database\Piggybank $repos */ - $repos = App::make('FireflyIII\Database\Piggybank'); - $data = Input::except('_token'); + $data = Input::except('_token'); + $data['rep_every'] = 0; + $data['reminder_skip'] = 0; + $data['order'] = 0; + $data['remind_me'] = isset($data['remind_me']) ? 1 : 0; + $data['user_id'] = Auth::user()->id; - switch (Input::get('post_submit_action')) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"'); - break; - case 'return_to_edit': - case 'update': - $messages = $repos->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save piggy bank: ' . $messages['errors']->first()); + // always validate: + $messages = $this->_repository->validate($data); - return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput()->withErrors($messages['errors']); - } - // store! - $repos->update($piggyBank, $data); - Event::fire('piggybank.update', [$piggyBank]); // new and used. - Session::flash('success', 'Piggy bank updated!'); - - if ($data['post_submit_action'] == 'return_to_edit') { - return Redirect::route('piggybanks.edit', $piggyBank->id); - } else { - return Redirect::route('piggybanks.index'); - } - case 'validate_only': - $messageBags = $repos->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not update piggy bank: ' . $messages['errors']->first()); } + // return to update screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput(); + } + + // update + $this->_repository->update($piggyBank, $data); + Session::flash('success', 'Piggy bank "' . e($data['name']) . '" updated.'); + + // go back to list + if ($data['post_submit_action'] == 'update') { + return Redirect::route('piggybanks.index'); + } + + // go back to update screen. + return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput(['post_submit_action' => 'return_to_edit']); } } \ No newline at end of file diff --git a/app/controllers/PreferencesController.php b/app/controllers/PreferencesController.php index 0d6a373843..1330af52ef 100644 --- a/app/controllers/PreferencesController.php +++ b/app/controllers/PreferencesController.php @@ -3,6 +3,8 @@ /** * Class PreferencesController * + * @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok. + * */ class PreferencesController extends BaseController { @@ -21,8 +23,8 @@ class PreferencesController extends BaseController */ public function index() { - /** @var \FireflyIII\Database\Account $acct */ - $acct = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $acct */ + $acct = App::make('FireflyIII\Database\Account\Account'); /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); @@ -30,9 +32,13 @@ class PreferencesController extends BaseController $accounts = $acct->getAssetAccounts(); $viewRange = $preferences->get('viewRange', '1M'); $viewRangeValue = $viewRange->data; - $frontpage = $preferences->get('frontpageAccounts', []); + $frontPage = $preferences->get('frontpageAccounts', []); + $budgetMax = $preferences->get('budgetMaximum', 1000); + $budgetMaximum = $budgetMax->data; - return View::make('preferences.index')->with('accounts', $accounts)->with('frontpageAccounts', $frontpage)->with('viewRange', $viewRangeValue); + return View::make('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontpageAccounts', $frontPage)->with( + 'viewRange', $viewRangeValue + ); } /** @@ -40,7 +46,6 @@ class PreferencesController extends BaseController */ public function postIndex() { - /** @var \FireflyIII\Shared\Preferences\Preferences $preferences */ $preferences = App::make('FireflyIII\Shared\Preferences\Preferences'); @@ -58,6 +63,11 @@ class PreferencesController extends BaseController Session::forget('end'); Session::forget('range'); + // budget maximum: + $budgetMaximum = intval(Input::get('budgetMaximum')); + $preferences->set('budgetMaximum', $budgetMaximum); + + Session::flash('success', 'Preferences saved!'); return Redirect::route('preferences'); diff --git a/app/controllers/ProfileController.php b/app/controllers/ProfileController.php index 938d41f28a..d5373ec0c5 100644 --- a/app/controllers/ProfileController.php +++ b/app/controllers/ProfileController.php @@ -32,7 +32,6 @@ class ProfileController extends BaseController { // old, new1, new2 - /** @noinspection PhpUndefinedFieldInspection */ if (!Hash::check(Input::get('old'), Auth::user()->password)) { Session::flash('error', 'Invalid current password!'); @@ -56,8 +55,8 @@ class ProfileController extends BaseController } // update the user with the new password. - /** @var \FireflyIII\Database\User $repository */ - $repository = \App::make('FireflyIII\Database\User'); + /** @var \FireflyIII\Database\User\User $repository */ + $repository = \App::make('FireflyIII\Database\User\User'); $repository->updatePassword(Auth::user(), Input::get('new1')); Session::flash('success', 'Password changed!'); diff --git a/app/controllers/RecurringController.php b/app/controllers/RecurringController.php index bd3a7faed6..84be23917a 100644 --- a/app/controllers/RecurringController.php +++ b/app/controllers/RecurringController.php @@ -49,8 +49,8 @@ class RecurringController extends BaseController { //Event::fire('recurring.destroy', [$recurringTransaction]); - /** @var \FireflyIII\Database\Recurring $repository */ - $repository = App::make('FireflyIII\Database\Recurring'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repository */ + $repository = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); $result = $repository->destroy($recurringTransaction); if ($result === true) { @@ -82,8 +82,8 @@ class RecurringController extends BaseController */ public function index() { - /** @var \FireflyIII\Database\Recurring $repos */ - $repos = App::make('FireflyIII\Database\Recurring'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */ + $repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); $recurring = $repos->get(); @@ -103,8 +103,8 @@ class RecurringController extends BaseController return Redirect::back(); } - /** @var \FireflyIII\Database\Recurring $repos */ - $repos = App::make('FireflyIII\Database\Recurring'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */ + $repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); $repos->scanEverything($recurringTransaction); Session::flash('success', 'Rescanned everything.'); @@ -135,8 +135,8 @@ class RecurringController extends BaseController public function store() { $data = Input::except('_token'); - /** @var \FireflyIII\Database\Recurring $repos */ - $repos = App::make('FireflyIII\Database\Recurring'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */ + $repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); switch ($data['post_submit_action']) { default: @@ -183,9 +183,11 @@ class RecurringController extends BaseController */ public function update(RecurringTransaction $recurringTransaction) { - /** @var \FireflyIII\Database\Recurring $repos */ - $repos = App::make('FireflyIII\Database\Recurring'); - $data = Input::except('_token'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repos */ + $repos = App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); + $data = Input::except('_token'); + $data['active'] = isset($data['active']) ? 1 : 0; + $data['automatch'] = isset($data['automatch']) ? 1 : 0; switch (Input::get('post_submit_action')) { default: diff --git a/app/controllers/RepeatedExpenseController.php b/app/controllers/RepeatedExpenseController.php index b3bdd762e0..71f821dfbc 100644 --- a/app/controllers/RepeatedExpenseController.php +++ b/app/controllers/RepeatedExpenseController.php @@ -1,21 +1,25 @@ _repository = $repository; } /** @@ -23,8 +27,8 @@ class RepeatedExpenseController extends BaseController */ public function create() { - /** @var \FireflyIII\Database\Account $acct */ - $acct = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $acct */ + $acct = App::make('FireflyIII\Database\Account\Account'); $periods = Config::get('firefly.piggybank_periods'); @@ -44,8 +48,8 @@ class RepeatedExpenseController extends BaseController $subTitle = 'Overview'; - /** @var \FireflyIII\Database\RepeatedExpense $repository */ - $repository = App::make('FireflyIII\Database\RepeatedExpense'); + /** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */ + $repository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense'); $expenses = $repository->get(); $expenses->each( @@ -67,13 +71,13 @@ class RepeatedExpenseController extends BaseController $subTitle = $piggyBank->name; $today = Carbon::now(); - /** @var \FireflyIII\Database\RepeatedExpense $repository */ - $repository = App::make('FireflyIII\Database\RepeatedExpense'); + /** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */ + $repository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense'); $repetitions = $piggyBank->piggybankrepetitions()->get(); $repetitions->each( function (PiggybankRepetition $repetition) use ($repository) { - $repository->calculateParts($repetition); + $repetition->bars = $repository->calculateParts($repetition); } ); @@ -86,50 +90,36 @@ class RepeatedExpenseController extends BaseController */ public function store() { - $data = Input::all(); + $data = Input::except('_token'); $data['repeats'] = 1; - /** @var \FireflyIII\Database\RepeatedExpense $repository */ - $repository = App::make('FireflyIII\Database\RepeatedExpense'); - switch ($data['post_submit_action']) { - default: - throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"'); - break; - case 'create_another': - case 'store': - $messages = $repository->validate($data); - /** @var MessageBag $messages ['errors'] */ - if ($messages['errors']->count() > 0) { - Session::flash('warnings', $messages['warnings']); - Session::flash('successes', $messages['successes']); - Session::flash('error', 'Could not save repeated expense: ' . $messages['errors']->first()); + // always validate: + $messages = $this->_repository->validate($data); - return Redirect::route('repeated.create')->withInput()->withErrors($messages['errors']); - } - // store! - $repeated = $repository->store($data); - - /* - * Create the relevant repetition per Event. - */ - Event::fire('piggybank.store', [$repeated]); // new and used. - - Session::flash('success', 'New repeated expense stored!'); - - if ($data['post_submit_action'] == 'create_another') { - return Redirect::route('repeated.create')->withInput(); - } else { - return Redirect::route('repeated.index'); - } - break; - case 'validate_only': - $messageBags = $repository->validate($data); - Session::flash('warnings', $messageBags['warnings']); - Session::flash('successes', $messageBags['successes']); - Session::flash('errors', $messageBags['errors']); - - return Redirect::route('repeated.create')->withInput(); - break; + // flash messages: + Session::flash('warnings', $messages['warnings']); + Session::flash('successes', $messages['successes']); + Session::flash('errors', $messages['errors']); + if ($messages['errors']->count() > 0) { + Session::flash('error', 'Could not validate repeated expense: ' . $messages['errors']->first()); } + // return to create screen: + if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) { + return Redirect::route('repeated.create')->withInput(); + } + + // store: + $this->_repository->store($data); + Session::flash('success', 'Budget "' . e($data['name']) . '" stored.'); + if ($data['post_submit_action'] == 'store') { + return Redirect::route('repeated.index'); + } + + // create another. + if ($data['post_submit_action'] == 'create_another') { + return Redirect::route('repeated.create')->withInput(); + } + + return Redirect::route('repeated.index'); } } \ No newline at end of file diff --git a/app/controllers/ReportController.php b/app/controllers/ReportController.php index 1bb335e453..96e806fa0b 100644 --- a/app/controllers/ReportController.php +++ b/app/controllers/ReportController.php @@ -1,11 +1,11 @@ _accounts = $accounts; $this->_journals = $journals; - $this->_reports = $reports; $this->_repository = $repository; } - /** - * @param $year - * @param $month - * - * @return \Illuminate\View\View - */ - public function budgets($year, $month) - { - try { - $start = new Carbon($year . '-' . $month . '-01'); - } catch (Exception $e) { - App::abort(500); - } - $end = clone $start; - $title = 'Reports'; - $subTitle = 'Budgets in ' . $start->format('F Y'); - $mainTitleIcon = 'fa-line-chart'; - $subTitleIcon = 'fa-bar-chart'; - - $end->endOfMonth(); - - - // get a list of all budgets and expenses. - /** @var \FireflyIII\Database\Budget $budgetRepository */ - $budgetRepository = App::make('FireflyIII\Database\Budget'); - - /** @var \FireflyIII\Database\Account $accountRepository */ - $accountRepository = App::make('FireflyIII\Database\Account'); - - - $budgets = $budgetRepository->get(); - - // calculate some stuff: - $budgets->each( - function (Budget $budget) use ($start, $end, $budgetRepository) { - $limitRepetitions = $budget->limitrepetitions()->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d'))->where( - 'enddate', '<=', $end->format( - 'Y-m-d' - ) - )->get(); - $repInfo = []; - /** @var LimitRepetition $repetition */ - foreach ($limitRepetitions as $repetition) { - $spent = $budgetRepository->spentInPeriod($budget, $start, $end); - if ($spent > floatval($repetition->amount)) { - // overspent! - $overspent = true; - $pct = floatval($repetition->amount) / $spent * 100; - - } else { - $overspent = false; - $pct = $spent / floatval($repetition->amount) * 100; - } - $pctDisplay = $spent / floatval($repetition->amount) * 100; - $repInfo[] = [ - 'date' => DateKit::periodShow($repetition->startdate, $repetition->limit->repeat_freq), - 'spent' => $spent, - 'budgeted' => floatval($repetition->amount), - 'left' => floatval($repetition->amount) - $spent, - 'pct' => ceil($pct), - 'pct_display' => ceil($pctDisplay), - 'overspent' => $overspent, - ]; - } - $budget->repInfo = $repInfo; - - } - ); - - $accounts = $accountRepository->getAssetAccounts(); - - $accounts->each( - function (Account $account) use ($start, $end, $accountRepository) { - $journals = $accountRepository->getTransactionJournalsInRange($account, $start, $end); - $budgets = []; - /** @var TransactionJournal $journal */ - foreach ($journals as $journal) { - $budgetId = isset($journal->budgets[0]) ? $journal->budgets[0]->id : 0; - $budgetName = isset($journal->budgets[0]) ? $journal->budgets[0]->name : '(no budget)'; - if (!isset($budgets[$budgetId])) { - $arr = [ - 'budget_id' => $budgetId, - 'budget_name' => $budgetName, - 'spent' => floatval($journal->getAmount()), - 'budgeted' => 0, - ]; - $budgets[$budgetId] = $arr; - } else { - $budgets[$budgetId]['spent'] += floatval($journal->getAmount()); - } - } - foreach ($budgets as $budgetId => $budget) { - $budgets[$budgetId]['left'] = $budget['budgeted'] - $budget['spent']; - } - $account->budgetInfo = $budgets; - } - ); - - - return View::make('reports.budgets', compact('start', 'end', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon', 'budgets', 'accounts')); - - } - /** * */ public function index() { $start = $this->_journals->firstDate(); - $months = $this->_reports->listOfMonths(clone $start); - $years = $this->_reports->listOfYears(clone $start); + $months = $this->_repository->listOfMonths(clone $start); + $years = $this->_repository->listOfYears(clone $start); $title = 'Reports'; $mainTitleIcon = 'fa-line-chart'; @@ -163,7 +55,7 @@ class ReportController extends BaseController public function unbalanced($year, $month) { try { - $date = new Carbon($year . '-' . $month . '-01'); + new Carbon($year . '-' . $month . '-01'); } catch (Exception $e) { App::abort(500); } @@ -175,61 +67,37 @@ class ReportController extends BaseController $subTitleIcon = 'fa-bar-chart'; $end->endOfMonth(); - /** @var \FireflyIII\Database\TransactionJournal $journalRepository */ - $journalRepository = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */ + $journalRepository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); + $journals = $journalRepository->getInDateRange($start, $end); - /* - * Get all journals from this month: - */ - $journals = $journalRepository->getInDateRange($start, $end); - - /* - * Filter withdrawals: - */ $withdrawals = $journals->filter( function (TransactionJournal $journal) { - if ($journal->transactionType->type == 'Withdrawal' && count($journal->budgets) == 0) { - - // count groups related to balance. - if ($journal->transactiongroups()->where('relation', 'balance')->count() == 0) { - return $journal; - } + $relations = $journal->transactiongroups()->where('relation', 'balance')->count(); + $budgets = $journal->budgets()->count(); + $type = $journal->transactionType->type; + if ($type == 'Withdrawal' && $budgets == 0 && $relations == 0) { + return $journal; } return null; } ); - /* - * Filter deposits. - */ $deposits = $journals->filter( function (TransactionJournal $journal) { - if ($journal->transactionType->type == 'Deposit' && count($journal->budgets) == 0) { - // count groups related to balance. - if ($journal->transactiongroups()->where('relation', 'balance')->count() == 0) { - return $journal; - } + $relations = $journal->transactiongroups()->where('relation', 'balance')->count(); + $budgets = $journal->budgets()->count(); + $type = $journal->transactionType->type; + if ($type == 'Deposit' && $budgets == 0 && $relations == 0) { + return $journal; } return null; } ); - - /* - * Filter transfers (not yet used) - */ - // $transfers = $journals->filter( - // function (TransactionJournal $journal) { - // if ($journal->transactionType->type == 'Transfer') { - // return $journal; - // } - // } - // ); - $journals = $withdrawals->merge($deposits); - return View::make('reports.unbalanced', compact('start', 'end', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon', 'journals')); } @@ -245,74 +113,21 @@ class ReportController extends BaseController } catch (Exception $e) { App::abort(500); } - $date = new Carbon('01-01-' . $year); + $date = new Carbon('01-01-' . $year); + $end = clone $date; + $end->endOfYear(); $title = 'Reports'; $subTitle = $year; $subTitleIcon = 'fa-bar-chart'; $mainTitleIcon = 'fa-line-chart'; - $balances = $this->_reports->yearBalanceReport($date); - $groupedIncomes = $this->_reports->groupByRevenue($date, 'income'); - $groupedExpenses = $this->_reports->groupByRevenue($date, 'expense'); - + $balances = $this->_repository->yearBalanceReport($date); + $groupedIncomes = $this->_repository->revenueGroupedByAccount($date, $end, 15); + $groupedExpenses = $this->_repository->expensesGroupedByAccount($date, $end, 15); return View::make( 'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') ); - - - /* - * For this year, get: - * - the sum of all expenses. - * - the sum of all incomes - * - per month, the sum of all expenses - * - per month, the sum of all incomes - * - 2x for shared and not-shared alike. - * - * - balance difference for all accounts. - */ - - $accounts = $accountRepository->getAssetAccounts(); - - // get some sums going - $summary = []; - - $end = clone $date; - $end->endOfYear(); - while ($date < $end) { - $month = $date->format('F'); - - $income = 0; - $incomeShared = 0; - $expense = 0; - $expenseShared = 0; - - foreach ($accounts as $account) { - if ($account->accountRole == 'sharedExpense') { - $incomeShared += $reportRepository->getIncomeByMonth($account, $date); - $expenseShared += $reportRepository->getExpenseByMonth($account, $date); - } else { - $income += $reportRepository->getIncomeByMonth($account, $date); - $expense += $reportRepository->getExpenseByMonth($account, $date); - } - } - - $summary[] = [ - 'month' => $month, - 'income' => $income, - 'expense' => $expense, - 'incomeShared' => $incomeShared, - 'expenseShared' => $expenseShared, - ]; - $date->addMonth(); - } - - - // draw some charts etc. - return View::make('reports.year', compact('summary', 'date'))->with('title', 'Reports')->with('mainTitleIcon', 'fa-line-chart')->with('subTitle', $year) - ->with( - 'subTitleIcon', 'fa-bar-chart' - )->with('year', $year); } } \ No newline at end of file diff --git a/app/controllers/TransactionController.php b/app/controllers/TransactionController.php index 5885f53f2d..7f1eb8ca3a 100644 --- a/app/controllers/TransactionController.php +++ b/app/controllers/TransactionController.php @@ -45,11 +45,11 @@ class TransactionController extends BaseController } } $unique = array_unique($ids); - if (count($ids) > 0) { + if (count($unique) > 0) { - /** @var \FireflyIII\Database\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal'); - $set = $repository->getByIds($ids); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); + $set = $repository->getByIds($unique); $set->each( function (TransactionJournal $journal) { $journal->amount = mf($journal->getAmount()); @@ -71,21 +71,17 @@ class TransactionController extends BaseController */ public function create($what = 'deposit') { - /* - * The repositories we need: - */ + /** @var \FireflyIII\Database\Account\Account $accountRepository */ + $accountRepository = App::make('FireflyIII\Database\Account\Account'); - /** @var \FireflyIII\Database\Account $accountRepository */ - $accountRepository = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ + $budgetRepository = App::make('FireflyIII\Database\Budget\Budget'); - /** @var \FireflyIII\Database\Budget $budgetRepository */ - $budgetRepository = App::make('FireflyIII\Database\Budget'); + /** @var \FireflyIII\Database\PiggyBank\PiggyBank $piggyRepository */ + $piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank'); - /** @var \FireflyIII\Database\Piggybank $piggyRepository */ - $piggyRepository = App::make('FireflyIII\Database\Piggybank'); - - /** @var \FireflyIII\Database\RepeatedExpense $repRepository */ - $repRepository = App::make('FireflyIII\Database\RepeatedExpense'); + /** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repRepository */ + $repRepository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense'); // get asset accounts with names and id's . $assetAccounts = FFForm::makeSelectList($accountRepository->getAssetAccounts()); @@ -100,9 +96,6 @@ class TransactionController extends BaseController $piggies[0] = '(no piggy bank)'; asort($piggies); - /* - * respond to a possible given values in the URL. - */ $preFilled = Session::has('preFilled') ? Session::get('preFilled') : []; $respondTo = ['account_id', 'account_from_id']; foreach ($respondTo as $r) { @@ -143,8 +136,8 @@ class TransactionController extends BaseController { $type = $transactionJournal->transactionType->type; - /** @var \FireflyIII\Database\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $repository->destroy($transactionJournal); $return = 'withdrawal'; @@ -172,8 +165,8 @@ class TransactionController extends BaseController $id = intval(Input::get('id')); $sister = intval(Input::get('relateTo')); - /** @var \FireflyIII\Database\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $journal = $repository->find($id); $sis = $repository->find($sister); @@ -207,39 +200,25 @@ class TransactionController extends BaseController * All the repositories we need: */ - /** @var \FireflyIII\Database\Account $accountRepository */ - $accountRepository = App::make('FireflyIII\Database\Account'); + /** @var \FireflyIII\Database\Account\Account $accountRepository */ + $accountRepository = App::make('FireflyIII\Database\Account\Account'); - /** @var \FireflyIII\Database\Budget $budgetRepository */ - $budgetRepository = App::make('FireflyIII\Database\Budget'); + /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ + $budgetRepository = App::make('FireflyIII\Database\Budget\Budget'); - /** @var \FireflyIII\Database\Piggybank $piggyRepository */ - $piggyRepository = App::make('FireflyIII\Database\Piggybank'); + /** @var \FireflyIII\Database\PiggyBank\PiggyBank $piggyRepository */ + $piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank'); // type is useful for display: $what = strtolower($journal->transactiontype->type); // get asset accounts with names and id's. + + $budgets = FFForm::makeSelectList($budgetRepository->get(), true); $accounts = FFForm::makeSelectList($accountRepository->getAssetAccounts()); + $piggies = FFForm::makeSelectList($piggyRepository->get(), true); - // get budgets as a select list. - $budgets = FFForm::makeSelectList($budgetRepository->get()); - $budgets[0] = '(no budget)'; - - /* - * Get all piggy banks plus (if any) the relevant piggy bank. Since just one - * of the transactions in the journal has this field, it should all fill in nicely. - */ - // get the piggy banks. - $piggies = FFForm::makeSelectList($piggyRepository->get()); - $piggies[0] = '(no piggy bank)'; - $piggyBankId = 0; - foreach ($journal->transactions as $t) { - if (!is_null($t->piggybank_id)) { - $piggyBankId = $t->piggybank_id; - } - } /* * Data to properly display the edit form. @@ -248,7 +227,7 @@ class TransactionController extends BaseController 'date' => $journal->date->format('Y-m-d'), 'category' => '', 'budget_id' => 0, - 'piggybank_id' => $piggyBankId + 'piggybank_id' => 0 ]; /* @@ -335,8 +314,8 @@ class TransactionController extends BaseController public function index($what) { - /** @var \FireflyIII\Database\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); switch ($what) { case 'expenses': @@ -396,8 +375,8 @@ class TransactionController extends BaseController { $search = e(trim(Input::get('searchValue'))); - /** @var \FireflyIII\Database\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $result = $repository->searchRelated($search, $journal); $result->each( @@ -456,8 +435,8 @@ class TransactionController extends BaseController $data['what'] = $what; $data['currency'] = 'EUR'; - /** @var \FireflyIII\Database\TransactionJournal $repository */ - $repository = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */ + $repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); switch ($data['post_submit_action']) { default: @@ -482,11 +461,7 @@ class TransactionController extends BaseController * Trigger a search for the related (if selected) * piggy bank and store an event. */ - $piggyID = null; - if (!is_null(Input::get('piggybank_id')) && intval(Input::get('piggybank_id')) > 0) { - $piggyID = intval(Input::get('piggybank_id')); - } - Event::fire('transactionJournal.store', [$journal, $piggyID]); // new and used. + Event::fire('transactionJournal.store', [$journal, Input::get('piggybank_id')]); // new and used. /* * Also trigger on both transactions. */ @@ -544,12 +519,13 @@ class TransactionController extends BaseController /** * @param TransactionJournal $journal * + * @return $this * @throws FireflyException */ public function update(TransactionJournal $journal) { - /** @var \FireflyIII\Database\TransactionJournal $repos */ - $repos = App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repos */ + $repos = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $data = Input::except('_token'); $data['currency'] = 'EUR'; diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index 5d101c850f..4cf00ce1a1 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -71,8 +71,8 @@ class UserController extends BaseController return View::make('error')->with('message', 'Not possible'); } - /** @var \FireflyIII\Database\User $repository */ - $repository = App::make('FireflyIII\Database\User'); + /** @var \FireflyIII\Database\User\User $repository */ + $repository = App::make('FireflyIII\Database\User\User'); /** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */ $email = App::make('FireflyIII\Shared\Mail\RegistrationInterface'); @@ -105,8 +105,8 @@ class UserController extends BaseController public function postRemindme() { - /** @var \FireflyIII\Database\User $repository */ - $repository = App::make('FireflyIII\Database\User'); + /** @var \FireflyIII\Database\User\User $repository */ + $repository = App::make('FireflyIII\Database\User\User'); /** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */ $email = App::make('FireflyIII\Shared\Mail\RegistrationInterface'); @@ -163,8 +163,8 @@ class UserController extends BaseController public function reset($reset) { - /** @var \FireflyIII\Database\User $repository */ - $repository = App::make('FireflyIII\Database\User'); + /** @var \FireflyIII\Database\User\User $repository */ + $repository = App::make('FireflyIII\Database\User\User'); /** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */ $email = App::make('FireflyIII\Shared\Mail\RegistrationInterface'); diff --git a/app/database/migrations/2014_06_27_163032_create_users_table.php b/app/database/migrations/2014_06_27_163032_create_users_table.php index ef3ebbabbe..3c72c3ab6c 100644 --- a/app/database/migrations/2014_06_27_163032_create_users_table.php +++ b/app/database/migrations/2014_06_27_163032_create_users_table.php @@ -5,8 +5,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateUsersTable - * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateUsersTable extends Migration { diff --git a/app/database/migrations/2014_06_27_163145_create_account_types_table.php b/app/database/migrations/2014_06_27_163145_create_account_types_table.php index 3c81582a50..7d90098389 100644 --- a/app/database/migrations/2014_06_27_163145_create_account_types_table.php +++ b/app/database/migrations/2014_06_27_163145_create_account_types_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateAccountTypesTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateAccountTypesTable extends Migration { diff --git a/app/database/migrations/2014_06_27_163259_create_accounts_table.php b/app/database/migrations/2014_06_27_163259_create_accounts_table.php index 8a7251f61f..71d3cd8a37 100644 --- a/app/database/migrations/2014_06_27_163259_create_accounts_table.php +++ b/app/database/migrations/2014_06_27_163259_create_accounts_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateAccountsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateAccountsTable extends Migration { diff --git a/app/database/migrations/2014_06_27_163817_create_components_table.php b/app/database/migrations/2014_06_27_163817_create_components_table.php index 605ef98205..2c4852f02c 100644 --- a/app/database/migrations/2014_06_27_163817_create_components_table.php +++ b/app/database/migrations/2014_06_27_163817_create_components_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateComponentsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateComponentsTable extends Migration { diff --git a/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php b/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php index 0587903fc0..5ac466d43e 100644 --- a/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php +++ b/app/database/migrations/2014_06_27_163818_create_piggybanks_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreatePiggybanksTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreatePiggybanksTable extends Migration { @@ -46,7 +45,7 @@ class CreatePiggybanksTable extends Migration $table->boolean('remind_me'); $table->integer('order')->unsigned(); - // connect account to piggybank. + // connect account to piggy bank. $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); // for an account, the name must be unique. diff --git a/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php b/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php index 8cecacf2e8..a6444da219 100644 --- a/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php +++ b/app/database/migrations/2014_06_27_164042_create_transaction_currencies_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateTransactionCurrenciesTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateTransactionCurrenciesTable extends Migration { diff --git a/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php b/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php index 568704210e..77a3d9924c 100644 --- a/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php +++ b/app/database/migrations/2014_06_27_164512_create_transaction_types_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateTransactionTypesTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateTransactionTypesTable extends Migration { diff --git a/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php b/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php index e37936f210..c3e9aea81b 100644 --- a/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php +++ b/app/database/migrations/2014_06_27_164619_create_recurring_transactions_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateRecurringTransactionsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateRecurringTransactionsTable extends Migration { diff --git a/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php b/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php index 7f751797c4..b44af8769c 100644 --- a/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php +++ b/app/database/migrations/2014_06_27_164620_create_transaction_journals_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateTransactionJournalsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateTransactionJournalsTable extends Migration { diff --git a/app/database/migrations/2014_06_27_164836_create_transactions_table.php b/app/database/migrations/2014_06_27_164836_create_transactions_table.php index 38453f93b6..74765c1910 100644 --- a/app/database/migrations/2014_06_27_164836_create_transactions_table.php +++ b/app/database/migrations/2014_06_27_164836_create_transactions_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateTransactionsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateTransactionsTable extends Migration { diff --git a/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php b/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php index 99e1d8649c..d5f73f8444 100644 --- a/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php +++ b/app/database/migrations/2014_06_27_165344_create_component_transaction_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateComponentTransactionTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateComponentTransactionTable extends Migration { @@ -18,7 +17,7 @@ class CreateComponentTransactionTable extends Migration */ public function down() { - Schema::drop('component_transaction'); + Schema::dropIfExists('component_transaction'); } /** diff --git a/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php b/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php index 4474c18ec7..2069e961a9 100644 --- a/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php +++ b/app/database/migrations/2014_07_05_171326_create_component_transaction_journal_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateComponentTransactionJournalTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateComponentTransactionJournalTable extends Migration { @@ -30,19 +29,19 @@ class CreateComponentTransactionJournalTable extends Migration { Schema::create( 'component_transaction_journal', function (Blueprint $table) { - $table->increments('id'); - $table->integer('component_id')->unsigned(); - $table->integer('transaction_journal_id')->unsigned(); + $table->increments('id'); + $table->integer('component_id')->unsigned(); + $table->integer('transaction_journal_id')->unsigned(); - // link components with component_id - $table->foreign('component_id')->references('id')->on('components')->onDelete('cascade'); + // link components with component_id + $table->foreign('component_id')->references('id')->on('components')->onDelete('cascade'); - // link transaction journals with transaction_journal_id - $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); + // link transaction journals with transaction_journal_id + $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); - // combo must be unique: - $table->unique(['component_id', 'transaction_journal_id'],'cid_tjid_unique'); - } + // combo must be unique: + $table->unique(['component_id', 'transaction_journal_id'], 'cid_tjid_unique'); + } ); } diff --git a/app/database/migrations/2014_07_06_123842_create_preferences_table.php b/app/database/migrations/2014_07_06_123842_create_preferences_table.php index 058c530f2a..61f12090a2 100644 --- a/app/database/migrations/2014_07_06_123842_create_preferences_table.php +++ b/app/database/migrations/2014_07_06_123842_create_preferences_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreatePreferencesTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreatePreferencesTable extends Migration { diff --git a/app/database/migrations/2014_07_09_204843_create_session_table.php b/app/database/migrations/2014_07_09_204843_create_session_table.php index c4423f33cf..3100f7e9b8 100644 --- a/app/database/migrations/2014_07_09_204843_create_session_table.php +++ b/app/database/migrations/2014_07_09_204843_create_session_table.php @@ -5,7 +5,6 @@ use Illuminate\Database\Migrations\Migration; /** * Class CreateSessionTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateSessionTable extends Migration { diff --git a/app/database/migrations/2014_07_17_183717_create_limits_table.php b/app/database/migrations/2014_07_17_183717_create_limits_table.php index fb3dbe3660..fced678780 100644 --- a/app/database/migrations/2014_07_17_183717_create_limits_table.php +++ b/app/database/migrations/2014_07_17_183717_create_limits_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateLimitsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateLimitsTable extends Migration { diff --git a/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php b/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php index e69902a3eb..1240cf3657 100644 --- a/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php +++ b/app/database/migrations/2014_07_19_055011_create_limit_repeat_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateLimitRepeatTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateLimitRepeatTable extends Migration { diff --git a/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php b/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php index e6f25ed2ec..512387e29b 100644 --- a/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php +++ b/app/database/migrations/2014_08_06_044416_create_component_recurring_transaction_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateComponentRecurringTransactionTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateComponentRecurringTransactionTable extends Migration { @@ -18,7 +17,7 @@ class CreateComponentRecurringTransactionTable extends Migration */ public function down() { - Schema::drop('component_recurring_transaction'); + Schema::dropIfExists('component_recurring_transaction'); } /** @@ -30,21 +29,21 @@ class CreateComponentRecurringTransactionTable extends Migration { Schema::create( 'component_recurring_transaction', function (Blueprint $table) { - $table->increments('id'); - $table->integer('component_id')->unsigned(); - $table->integer('recurring_transaction_id')->unsigned(); - $table->boolean('optional'); + $table->increments('id'); + $table->integer('component_id')->unsigned(); + $table->integer('recurring_transaction_id')->unsigned(); + $table->boolean('optional'); - // link components with component_id - $table->foreign('component_id')->references('id')->on('components')->onDelete('cascade'); + // link components with component_id + $table->foreign('component_id')->references('id')->on('components')->onDelete('cascade'); - // link transaction journals with transaction_journal_id - $table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('cascade'); + // link transaction journals with transaction_journal_id + $table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('cascade'); - // component and recurring transaction must be unique. - $table->unique(['component_id','recurring_transaction_id'],'cid_rtid_unique'); + // component and recurring transaction must be unique. + $table->unique(['component_id', 'recurring_transaction_id'], 'cid_rtid_unique'); - } + } ); } diff --git a/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php b/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php index 5a8fa36282..d285d99487 100644 --- a/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php +++ b/app/database/migrations/2014_08_12_173919_create_piggybank_repetitions_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreatePiggyInstance * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreatePiggybankRepetitionsTable extends Migration { diff --git a/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php b/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php index f598185157..480f09d658 100644 --- a/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php +++ b/app/database/migrations/2014_08_18_100330_create_piggybank_events_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreatePiggybankEventsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreatePiggybankEventsTable extends Migration { diff --git a/app/database/migrations/2014_08_23_113221_create_reminders_table.php b/app/database/migrations/2014_08_23_113221_create_reminders_table.php index 7a3cbc0997..8d231aac04 100644 --- a/app/database/migrations/2014_08_23_113221_create_reminders_table.php +++ b/app/database/migrations/2014_08_23_113221_create_reminders_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateRemindersTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateRemindersTable extends Migration { diff --git a/app/database/migrations/2014_11_10_172053_create_account_meta_table.php b/app/database/migrations/2014_11_10_172053_create_account_meta_table.php index e465b7a5eb..0cbc84ae4d 100644 --- a/app/database/migrations/2014_11_10_172053_create_account_meta_table.php +++ b/app/database/migrations/2014_11_10_172053_create_account_meta_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateAccountMetaTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateAccountMetaTable extends Migration { diff --git a/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php b/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php index 31dca7cda5..acba3c84ce 100644 --- a/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php +++ b/app/database/migrations/2014_11_29_135749_create_transaction_groups_table.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint; /** * Class CreateTransactionGroupsTable * - * @SuppressWarnings(PHPMD.ShortMethodName) */ class CreateTransactionGroupsTable extends Migration { diff --git a/app/database/migrations/2014_12_13_190730_changes_for_v321.php b/app/database/migrations/2014_12_13_190730_changes_for_v321.php new file mode 100644 index 0000000000..7185cde1b8 --- /dev/null +++ b/app/database/migrations/2014_12_13_190730_changes_for_v321.php @@ -0,0 +1,634 @@ +moveBudgetsBack(); // 1. + $this->moveCategoriesBack(); // 2. + $this->createComponentId(); // 3. + $this->updateComponentInBudgetLimits(); // 4. + $this->createComponentIdForeignKey(); // 5. + $this->dropBudgetIdColumnInBudgetLimits(); // 6. + $createComponents = new CreateComponentTransactionJournalTable; // 7. + $createComponents->up(); + $this->moveBackEntriesForBudgetsInJoinedTable(); // 8. + $this->moveBackEntriesForCategoriesInJoinedTable(); // 9. + $this->dropBudgetJournalTable(); // 10. + $this->dropCategoryJournalTable(); // 11. + $this->dropBudgetTable(); // 12. + $this->dropCategoryTable(); // 13. + $this->renameBudgetLimits(); // 14. + $this->renamePiggyBankEvents(); // 15. + $this->renameBudgetLimitToBudgetInRepetitions(); // 16. + // 17, 18, 19 + $this->dropFieldsFromCurrencyTable(); // 20. + + + } + + public function moveBudgetsBack() + { + Budget::get()->each( + function (Budget $budget) { + Component::firstOrCreate( + [ + 'name' => $budget->name, + 'user_id' => $budget->user_id, + 'class' => 'Budget' + ] + ); + } + ); + } + + public function moveCategoriesBack() + { + Category::get()->each( + function (Category $category) { + Component::firstOrCreate( + [ + 'name' => $category->name, + 'user_id' => $category->user_id, + 'class' => 'Category' + ] + ); + } + ); + } + + public function createComponentId() + { + Schema::table( + 'budget_limits', function (Blueprint $table) { + $table->integer('component_id')->unsigned(); + } + ); + } + + public function updateComponentInBudgetLimits() + { + BudgetLimit::get()->each( + function (BudgetLimit $bl) { + $budgetId = $bl->budget_id; + $budget = Budget::find($budgetId); + if ($budget) { + $component = Component::where('class', 'Budget')->where('user_id', $budget->user_id)->where('name', $budget->name)->first(); + if ($component) { + $bl->component_id = $component->id; + $bl->save(); + } + } + } + ); + } + + public function createComponentIdForeignKey() + { + Schema::table( + 'budget_limits', function (Blueprint $table) { + $table->foreign('component_id', 'limits_component_id_foreign')->references('id')->on('components')->onDelete('cascade'); + } + ); + } + + public function dropBudgetIdColumnInBudgetLimits() + { + Schema::table( + 'budget_limits', function (Blueprint $table) { + $table->dropForeign('bid_foreign'); + $table->dropColumn('budget_id'); // also drop foreign key! + } + ); + } + + public function moveBackEntriesForBudgetsInJoinedTable() + { + $set = DB::table('budget_transaction_journal')->get(); + foreach ($set as $entry) { + $budget = Budget::find($entry->budget_id); + if ($budget) { + $component = Component::where('class', 'Budget')->where('name', $budget->name)->where('user_id', $budget->user_id)->first(); + if ($component) { + DB::table('component_transaction_journal')->insert( + [ + 'component_id' => $component->id, + 'transaction_journal_id' => $entry->transaction_journal_id + ] + ); + } + + } + } + + } + + public function moveBackEntriesForCategoriesInJoinedTable() + { + $set = DB::table('category_transaction_journal')->get(); + foreach ($set as $entry) { + $category = Category::find($entry->category_id); + if ($category) { + $component = Component::where('class', 'Category')->where('name', $category->name)->where('user_id', $category->user_id)->first(); + if ($component) { + DB::table('component_transaction_journal')->insert( + [ + 'component_id' => $component->id, + 'transaction_journal_id' => $entry->transaction_journal_id + ] + ); + } + + } + } + + } + + public function dropBudgetJournalTable() + { + Schema::dropIfExists('budget_transaction_journal'); + } + + public function dropCategoryJournalTable() + { + Schema::dropIfExists('category_transaction_journal'); + } + + public function dropBudgetTable() + { + Schema::dropIfExists('budgets'); + } + + public function dropCategoryTable() + { + Schema::dropIfExists('categories'); + } + + public function renameBudgetLimits() + { + Schema::rename('budget_limits', 'limits'); + } + + public function renamePiggyBankEvents() + { + Schema::rename('piggy_bank_events', 'piggybank_events'); + + } + + public function renameBudgetLimitToBudgetInRepetitions() + { + Schema::table( + 'limit_repetitions', function (Blueprint $table) { + $table->renameColumn('budget_limit_id', 'limit_id'); + } + ); + } + + public function dropFieldsFromCurrencyTable() + { + + Schema::table( + 'transaction_currencies', function (Blueprint $table) { + $table->dropColumn('symbol'); + $table->dropColumn('name'); + } + ); + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $this->createBudgetTable(); // 1. + $this->createCategoryTable(); // 2. + $this->createBudgetJournalTable(); // 3 + $this->createCategoryJournalTable(); // 4. + $this->moveBudgets(); // 5. + $this->moveCategories(); // 6. + $this->correctNameForBudgetLimits(); // 7. + $this->correctNameForPiggyBankEvents(); // 8. + $this->renameBudgetToBudgetLimitInRepetitions(); // 9. + $this->addBudgetIdFieldToBudgetLimits(); // 10. + $this->moveComponentIdToBudgetId(); // 11. + $this->dropComponentJournalTable(); // 12. + $this->dropComponentRecurringTransactionTable(); // 13. + $this->dropComponentTransactionTable(); // 14. + $this->dropPiggyBankIdFromTransactions(); // 15. + $this->dropComponentIdFromBudgetLimits(); // 16. + $this->expandCurrencyTable(); // 17. + + + // $this->doRenameInLimitRepetitions(); + // $this->doBudgetLimits(); + // $this->doPiggyBankEvents(); + // $this->doCreateCategoryTables(); + // $this->doUpdateTransactionTable(); + // $this->doDropCompRecurTable(); + // $this->doDropCompTransTable(); + // $this->doMoveBudgets(); + // $this->doMoveCategories(); + // $this->doMoveLimitReferences(); + + + } + + public function createBudgetTable() + { + Schema::create( + 'budgets', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->string('name', 50); + $table->integer('user_id')->unsigned(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->unique(['user_id', 'name']); + } + ); + + + } + + public function createCategoryTable() + { + Schema::create( + 'categories', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->string('name', 50); + $table->integer('user_id')->unsigned(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->unique(['user_id', 'name']); + } + ); + } + + public function createBudgetJournalTable() + { + Schema::create( + 'budget_transaction_journal', function (Blueprint $table) { + $table->increments('id'); + $table->integer('budget_id')->unsigned(); + $table->integer('transaction_journal_id')->unsigned(); + $table->foreign('budget_id')->references('id')->on('budgets')->onDelete('cascade'); + $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); + $table->unique(['budget_id', 'transaction_journal_id'], 'budid_tjid_unique'); + } + ); + } + + public function createCategoryJournalTable() + { + Schema::create( + 'category_transaction_journal', function (Blueprint $table) { + $table->increments('id'); + $table->integer('category_id')->unsigned(); + $table->integer('transaction_journal_id')->unsigned(); + $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); + $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); + $table->unique(['category_id', 'transaction_journal_id'], 'catid_tjid_unique'); + } + ); + } + + public function moveBudgets() + { + Component::where('class', 'Budget')->get()->each( + function (Component $c) { + $entry = [ + 'user_id' => $c->user_id, + 'name' => $c->name + + ]; + $budget = Budget::firstOrCreate($entry); + Log::debug('Migrated budget #' . $budget->id . ': ' . $budget->name); + // create entry in budget_transaction_journal + $connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get(); + foreach ($connections as $connection) { + DB::table('budget_transaction_journal')->insert( + [ + 'budget_id' => $budget->id, + 'transaction_journal_id' => $connection->transaction_journal_id + ] + ); + } + } + ); + } + + public function moveCategories() + { + Component::where('class', 'Category')->get()->each( + function (Component $c) { + $entry = [ + 'user_id' => $c->user_id, + 'name' => $c->name + + ]; + $category = Category::firstOrCreate($entry); + Log::debug('Migrated category #' . $category->id . ': ' . $category->name); + // create entry in category_transaction_journal + $connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get(); + foreach ($connections as $connection) { + DB::table('category_transaction_journal')->insert( + [ + 'category_id' => $category->id, + 'transaction_journal_id' => $connection->transaction_journal_id + ] + ); + } + } + ); + } + + public function correctNameForBudgetLimits() + { + Schema::rename('limits', 'budget_limits'); + } + + public function correctNameForPiggyBankEvents() + { + Schema::rename('piggybank_events', 'piggy_bank_events'); + + } + + public function renameBudgetToBudgetLimitInRepetitions() + { + Schema::table( + 'limit_repetitions', function (Blueprint $table) { + $table->renameColumn('limit_id', 'budget_limit_id'); + } + ); + } + + public function addBudgetIdFieldToBudgetLimits() + { + Schema::table( + 'budget_limits', function (Blueprint $table) { + $table->integer('budget_id', false, true)->nullable()->after('updated_at'); + $table->foreign('budget_id', 'bid_foreign')->references('id')->on('budgets')->onDelete('cascade'); + } + ); + } + + public function moveComponentIdToBudgetId() + { + \Log::debug('Now in moveComponentIdToBudgetId()'); + BudgetLimit::get()->each( + function (BudgetLimit $bl) { + \Log::debug('Now at budgetLimit #' . $bl->id . ' with component_id: ' . $bl->component_id); + $component = Component::find($bl->component_id); + if ($component) { + \Log::debug('Found component with id #' . $component->id . ' and name ' . $component->name); + $budget = Budget::whereName($component->name)->whereUserId($component->user_id)->first(); + if ($budget) { + \Log::debug('Found a budget with ID #' . $budget->id . ' and name ' . $budget->name); + $bl->budget_id = $budget->id; + $bl->save(); + \Log::debug('Connected budgetLimit #' . $bl->id . ' to budget_id' . $budget->id); + } else { + \Log::debug('Could not find a matching budget with name ' . $component->name); + } + } else { + \Log::debug('Could not find a component with id ' . $bl->component_id); + } + } + ); + \Log::debug('Done with moveComponentIdToBudgetId()'); + + } + + public function dropComponentJournalTable() + { + Schema::dropIfExists('component_transaction_journal'); + } + + public function dropComponentRecurringTransactionTable() + { + Schema::dropIfExists('component_recurring_transaction'); + } + + public function dropComponentTransactionTable() + { + Schema::dropIfExists('component_transaction'); + } + + public function dropPiggyBankIdFromTransactions() + { + + Schema::table( + 'transactions', function (Blueprint $table) { + if (Schema::hasColumn('transactions', 'piggybank_id')) { + $table->dropForeign('transactions_piggybank_id_foreign'); + $table->dropColumn('piggybank_id'); + } + } + ); + } + + public function dropComponentIdFromBudgetLimits() + { + Schema::table( + 'budget_limits', function (Blueprint $table) { + $table->dropForeign('limits_component_id_foreign'); + $table->dropColumn('component_id'); + } + ); + } + + public function expandCurrencyTable() + { + Schema::table( + 'transaction_currencies', function (Blueprint $table) { + $table->string('name', 48)->nullable(); + $table->string('symbol', 8)->nullable(); + } + ); + \DB::update('UPDATE `transaction_currencies` SET `symbol` = "€", `name` = "Euro" WHERE `code` = "EUR";'); + } + + // + // public function doRenameInLimitRepetitions() + // { + // Schema::table( + // 'limit_repetitions', function (Blueprint $table) { + // $table->renameColumn('limit_id', 'budget_limit_id'); + // } + // ); + // } + // + // public function doBudgetLimits() + // { + // Schema::rename('limits', 'budget_limits'); + // Schema::table( + // 'budget_limits', function (Blueprint $table) { + // $table->integer('budget_id')->unsigned()->after('updated_at'); + // $table->foreign('budget_id', 'bid_foreign')->references('id')->on('budgets')->onDelete('cascade'); + // } + // ); + // } + // + // public function doPiggyBankEvents() + // { + // Schema::rename('piggybank_events', 'piggy_bank_events'); + // + // } + // + // public function doCreateCategoryTables() + // { + // Schema::create( + // 'categories', function (Blueprint $table) { + // $table->increments('id'); + // $table->timestamps(); + // $table->softDeletes(); + // $table->string('name', 50); + // $table->integer('user_id')->unsigned(); + // $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + // $table->unique(['user_id', 'name']); + // } + // ); + // Schema::create( + // 'category_transaction_journal', function (Blueprint $table) { + // $table->increments('id'); + // $table->integer('category_id')->unsigned(); + // $table->integer('transaction_journal_id')->unsigned(); + // $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); + // $table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade'); + // $table->unique(['category_id', 'transaction_journal_id'], 'catid_tjid_unique'); + // } + // ); + // + // } + // + // public function doUpdateTransactionTable() + // { + // Schema::table( + // 'transactions', function (Blueprint $table) { + // $table->dropForeign('transactions_piggybank_id_foreign'); + // #$table->dropIndex('transactions_piggybank_id_foreign'); + // $table->dropColumn('piggybank_id'); + // } + // ); + // } + // + // public function doDropCompRecurTable() + // { + // Schema::drop('component_recurring_transaction'); + // } + // + // public function doDropCompTransTable() + // { + // Schema::drop('component_transaction'); + // } + // + // public function doMoveBudgets() + // { + // Component::where('class', 'Budget')->get()->each( + // function (Component $c) { + // $entry = [ + // 'user_id' => $c->user_id, + // 'name' => $c->name + // + // ]; + // $budget = Budget::firstOrCreate($entry); + // Log::debug('Migrated budget #' . $budget->id . ': ' . $budget->name); + // // create entry in budget_transaction_journal + // $connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get(); + // foreach ($connections as $connection) { + // DB::table('budget_transaction_journal')->insert( + // [ + // 'budget_id' => $budget->id, + // 'transaction_journal_id' => $connection->transaction_journal_id + // ] + // ); + // } + // } + // ); + // } + // + // public function doMoveCategories() + // { + // Component::where('class', 'Category')->get()->each( + // function (Component $c) { + // $entry = [ + // 'user_id' => $c->user_id, + // 'name' => $c->name + // + // ]; + // $category = Category::firstOrCreate($entry); + // Log::debug('Migrated category #' . $category->id . ': ' . $category->name); + // // create entry in category_transaction_journal + // $connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get(); + // foreach ($connections as $connection) { + // DB::table('category_transaction_journal')->insert( + // [ + // 'category_id' => $category->id, + // 'transaction_journal_id' => $connection->transaction_journal_id + // ] + // ); + // } + // } + // ); + // } + // + // public function doMoveLimitReferences() + // { + // throw new \FireflyIII\Exception\FireflyException('TODO'); + // } + +} diff --git a/app/database/production.sqlite b/app/database/production.sqlite deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/app/database/seeds/DefaultUserSeeder.php b/app/database/seeds/DefaultUserSeeder.php index 0e4c292529..4198ae4134 100644 --- a/app/database/seeds/DefaultUserSeeder.php +++ b/app/database/seeds/DefaultUserSeeder.php @@ -8,17 +8,11 @@ class DefaultUserSeeder extends Seeder public function run() { DB::table('users')->delete(); - if (App::environment() == 'testing') { + if (App::environment() == 'testing' || App::environment() == 'homestead') { - User::create( - ['email' => 'thegrumpydictator@gmail.com', 'password' => 'james', 'reset' => null, 'remember_token' => null, 'migrated' => 0] - ); - User::create( - ['email' => 'acceptance@example.com', 'password' => 'acceptance', 'reset' => null, 'remember_token' => null, 'migrated' => 0] - ); - User::create( - ['email' => 'functional@example.com', 'password' => 'functional', 'reset' => null, 'remember_token' => null, 'migrated' => 0] - ); + User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => 'james', 'reset' => null, 'remember_token' => null]); + User::create(['email' => 'acceptance@example.com', 'password' => 'acceptance', 'reset' => null, 'remember_token' => null]); + User::create(['email' => 'functional@example.com', 'password' => 'functional', 'reset' => null, 'remember_token' => null]); } } diff --git a/app/database/seeds/TestContentSeeder.php b/app/database/seeds/TestContentSeeder.php index 202b8ebd11..dabac9f474 100644 --- a/app/database/seeds/TestContentSeeder.php +++ b/app/database/seeds/TestContentSeeder.php @@ -2,20 +2,21 @@ use Carbon\Carbon; +/** + * Class TestContentSeeder + */ class TestContentSeeder extends Seeder { public function run() { - if (App::environment() == 'testing') { + if (App::environment() == 'testing' || App::environment() == 'homestead') { $assetType = AccountType::whereType('Asset account')->first(); $expenseType = AccountType::whereType('Expense account')->first(); $revenueType = AccountType::whereType('Revenue account')->first(); $ibType = AccountType::whereType('Initial balance account')->first(); - $euro = TransactionCurrency::whereCode('EUR')->first(); - $obType = TransactionType::whereType('Opening balance')->first(); $withdrawal = TransactionType::whereType('Withdrawal')->first(); $transfer = TransactionType::whereType('Transfer')->first(); @@ -27,18 +28,147 @@ class TestContentSeeder extends Seeder // create two asset accounts. $checking = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Checking account', 'active' => 1]); $savings = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Savings account', 'active' => 1]); + Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]); // create two budgets: $groceriesBudget = Budget::create(['user_id' => $user->id, 'name' => 'Groceries']); $billsBudget = Budget::create(['user_id' => $user->id, 'name' => 'Bills']); + $deleteBudget = Budget::create(['user_id' => $user->id, 'name' => 'Delete me']); + + // some limits: + $startDate = Carbon::now()->startOfMonth(); + $endDate = Carbon::now()->endOfMonth(); + $secondStart = Carbon::now()->subMonth()->startOfMonth(); + $secondEnd = Carbon::now()->subMonth()->endOfMonth(); + $limitOne = BudgetLimit::create( + ['startdate' => $startDate->format('Y-m-d'), 'amount' => 201, 'repeats' => 0, 'repeat_freq' => 'monthly', + 'budget_id' => $groceriesBudget->id] + ); + $limitTwo = BudgetLimit::create( + ['startdate' => $secondStart->format('Y-m-d'), 'amount' => 202, 'repeats' => 0, 'repeat_freq' => 'monthly', + 'budget_id' => $billsBudget->id] + ); + $limitThree = BudgetLimit::create( + ['startdate' => '2014-01-01', 'amount' => 203, 'repeats' => 0, 'repeat_freq' => 'monthly', + 'budget_id' => $deleteBudget->id] + ); + + // and because we have no filters, some repetitions: + $repOne = LimitRepetition::create( + ['budget_limit_id' => $limitOne->id, 'startdate' => $startDate->format('Y-m-d'), 'enddate' => $endDate->format('Y-m-d'), 'amount' => 201] + ); + $repTwo = LimitRepetition::create( + ['budget_limit_id' => $limitTwo->id, 'startdate' => $secondStart->format('Y-m-d'), 'enddate' => $secondEnd->format('Y-m-d'), 'amount' => 202] + ); + $repThree = LimitRepetition::create( + ['budget_limit_id' => $limitThree->id, 'startdate' => '2014-01-01', 'enddate' => '2014-01-31', 'amount' => 203] + ); // create two categories: - $dailyGroceries = Category::create(['user_id' => $user->id, 'name' => 'Daily groceries']); + $dailyGroceries = Category::create(['user_id' => $user->id, 'name' => 'DailyGroceries']); $lunch = Category::create(['user_id' => $user->id, 'name' => 'Lunch']); $house = Category::create(['user_id' => $user->id, 'name' => 'House']); + $deleteMe = Category::create(['user_id' => $user->id, 'name' => 'Delete me']); + + Component::create(['user_id' => $user->id, 'name' => 'Some Component 1', 'class' => 'Budget']); + Component::create(['user_id' => $user->id, 'name' => 'Some Component 2', 'class' => 'Budget']); + Component::create(['user_id' => $user->id, 'name' => 'Some Component 3', 'class' => 'Budget']); + Component::create(['user_id' => $user->id, 'name' => 'Some Component 4', 'class' => 'Category']); + Component::create(['user_id' => $user->id, 'name' => 'Some Component 5', 'class' => 'Category']); + Component::create(['user_id' => $user->id, 'name' => 'Some Component 6', 'class' => 'Category']); + Component::create(['user_id' => $user->id, 'name' => 'Some Component 7', 'class' => 'Category']); + + // piggy bank + $piggy = Piggybank::create( + [ + 'account_id' => $savings->id, + 'name' => 'New camera', + 'targetamount' => 2000, + 'startdate' => Carbon::now()->format('Y-m-d'), + 'targetdate' => null, + 'repeats' => 0, + 'rep_length' => null, + 'rep_every' => 0, + 'rep_times' => null, + 'reminder' => null, + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 0, + ] + ); + PiggyBankEvent::create(['piggybank_id' => 1, 'date' => $startDate->format('Y-m-d'), 'amount' => 100]); + PiggybankRepetition::create( + [ + 'piggybank_id' => $piggy->id, + 'startdate' => Carbon::now()->format('Y-m-d'), + 'targetdate' => null, + 'currentamount' => 0 + ] + ); + + // piggy bank + $piggyTargeted = Piggybank::create( + [ + 'account_id' => $savings->id, + 'name' => 'New clothes', + 'targetamount' => 2000, + 'startdate' => Carbon::now()->format('Y-m-d'), + 'targetdate' => Carbon::now()->addMonths(4)->format('Y-m-d'), + 'repeats' => 0, + 'rep_length' => null, + 'rep_every' => 0, + 'rep_times' => null, + 'reminder' => null, + 'reminder_skip' => 0, + 'remind_me' => 0, + 'order' => 0, + ] + ); + + PiggyBankEvent::create(['piggybank_id' => $piggyTargeted->id, 'date' => $startDate->format('Y-m-d'), 'amount' => 100]); + PiggybankRepetition::create( + [ + 'piggybank_id' => $piggyTargeted->id, + 'startdate' => Carbon::now()->format('Y-m-d'), + 'targetdate' => Carbon::now()->addMonths(4)->format('Y-m-d'), + 'currentamount' => 0 + ] + ); + + // recurring transaction + $recurring = \RecurringTransaction::create( + [ + 'user_id' => $user->id, + 'name' => 'Huur', + 'match' => 'huur,portaal', + 'amount_min' => 500, + 'amount_max' => 700, + 'date' => '2014-01-12', + 'active' => 1, + 'automatch' => 1, + 'repeat_freq' => 'monthly', + 'skip' => 0, + ] + ); + + // recurring transaction + $secondRecurring = \RecurringTransaction::create( + [ + 'user_id' => $user->id, + 'name' => 'Gas licht', + 'match' => 'no,match', + 'amount_min' => 500, + 'amount_max' => 700, + 'date' => '2014-01-12', + 'active' => 1, + 'automatch' => 1, + 'repeat_freq' => 'monthly', + 'skip' => 0, + ] + ); // create some expense accounts. - $ah = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Albert Heijn', 'active' => 1]); + $albert = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Albert Heijn', 'active' => 1]); $plus = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'PLUS', 'active' => 1]); $vitens = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Vitens', 'active' => 1]); $greenchoice = Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Greenchoice', 'active' => 1]); @@ -48,7 +178,7 @@ class TestContentSeeder extends Seeder // create three revenue accounts. $employer = Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Employer', 'active' => 1]); $taxes = Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'IRS', 'active' => 1]); - $job = Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Job', 'active' => 1]); + Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Job', 'active' => 1]); // put money in the two accounts (initial balance) $ibChecking = Account::create( @@ -64,10 +194,11 @@ class TestContentSeeder extends Seeder // create some expenses and incomes and what-not (for every month): $start = new Carbon('2014-01-01'); - $end = Carbon::now()->startOfMonth()->subDay(); + $end = Carbon::now()->endOfMonth()->addDay(); while ($start <= $end) { $this->createTransaction( - $checking, $portaal, 500, $withdrawal, 'Rent for ' . $start->format('F Y'), $start->format('Y-m-') . '01', $billsBudget, $house + $checking, $portaal, 500, $withdrawal, 'Huur Portaal for ' . $start->format('F Y'), $start->format('Y-m-') . '01', $billsBudget, $house, + $recurring ); $this->createTransaction( $checking, $vitens, 12, $withdrawal, 'Water for ' . $start->format('F Y'), $start->format('Y-m-') . '02', $billsBudget, $house @@ -87,7 +218,7 @@ class TestContentSeeder extends Seeder $groceriesStart->addDay(); if (intval($groceriesStart->format('d')) % 2 == 0) { $this->createTransaction( - $checking, $ah, $amt, $withdrawal, 'Groceries', $groceriesStart->format('Y-m-d'), $groceriesBudget, $dailyGroceries + $checking, $albert, $amt, $withdrawal, 'Groceries', $groceriesStart->format('Y-m-d'), $groceriesBudget, $dailyGroceries ); } $groceriesStart->addDay(); @@ -121,30 +252,37 @@ class TestContentSeeder extends Seeder } /** - * @param Account $from - * @param Account $to - * @param $amount - * @param TransactionType $type - * @param $description - * @param $date + * @param Account $from + * @param Account $to + * @param $amount + * @param TransactionType $type + * @param $description + * @param $date + * + * @param Budget $budget + * @param Category $category + * @param RecurringTransaction $recurring * * @return TransactionJournal */ public function createTransaction( - Account $from, Account $to, $amount, TransactionType $type, $description, $date, Budget $budget = null, Category $category = null + Account $from, Account $to, $amount, TransactionType $type, $description, $date, Budget $budget = null, Category $category = null, + $recurring = null ) { - $user = User::whereEmail('thegrumpydictator@gmail.com')->first(); - $euro = TransactionCurrency::whereCode('EUR')->first(); + $user = User::whereEmail('thegrumpydictator@gmail.com')->first(); + $euro = TransactionCurrency::whereCode('EUR')->first(); + $recurringID = is_null($recurring) ? null : $recurring->id; /** @var TransactionJournal $journal */ $journal = TransactionJournal::create( [ - 'user_id' => $user->id, - 'transaction_type_id' => $type->id, - 'transaction_currency_id' => $euro->id, - 'description' => $description, - 'completed' => 1, - 'date' => $date + 'user_id' => $user->id, + 'transaction_type_id' => $type->id, + 'transaction_currency_id' => $euro->id, + 'recurring_transaction_id' => $recurringID, + 'description' => $description, + 'completed' => 1, + 'date' => $date ] ); @@ -154,7 +292,6 @@ class TestContentSeeder extends Seeder 'transaction_journal_id' => $journal->id, 'amount' => $amount * -1 ] - ); Transaction::create( [ @@ -162,7 +299,6 @@ class TestContentSeeder extends Seeder 'transaction_journal_id' => $journal->id, 'amount' => $amount ] - ); if (!is_null($budget)) { $journal->budgets()->save($budget); diff --git a/app/database/seeds/TransactionCurrencySeeder.php b/app/database/seeds/TransactionCurrencySeeder.php index 46a08f74fb..20f50e9f60 100644 --- a/app/database/seeds/TransactionCurrencySeeder.php +++ b/app/database/seeds/TransactionCurrencySeeder.php @@ -10,9 +10,8 @@ class TransactionCurrencySeeder extends Seeder { DB::table('transaction_currencies')->delete(); - TransactionCurrency::create( - ['code' => 'EUR'] - ); + TransactionCurrency::create(['code' => 'EUR','name' => 'Euro','symbol' => '€']); + TransactionCurrency::create(['code' => 'USD','name' => 'US Dollar','symbol' => '$']); } } \ No newline at end of file diff --git a/app/filters.php b/app/filters.php index a55467f0e3..8a73c6b6da 100644 --- a/app/filters.php +++ b/app/filters.php @@ -4,11 +4,15 @@ App::before( function ($request) { + + // put IP in session if not already there. + $reminders = []; if (Auth::check()) { Filter::setSessionDateRange(); Reminders::updateReminders(); + Steam::removeEmptyBudgetLimits(); $reminders = Reminders::getReminders(); } View::share('reminders', $reminders); diff --git a/app/lib/Firefly/Database/SingleTableInheritanceEntity.php b/app/lib/Firefly/Database/SingleTableInheritanceEntity.php deleted file mode 100644 index 762ee14ad6..0000000000 --- a/app/lib/Firefly/Database/SingleTableInheritanceEntity.php +++ /dev/null @@ -1,121 +0,0 @@ -mapData((array)$attributes)->newInstance([], true); - $instance->setRawAttributes((array)$attributes, true); - - return $instance; - } - - - /** - * if no subclass is defined, function as normal - * - * @param array $attributes - * - * @return \Illuminate\Database\Eloquent\Model|static - */ - public function mapData(array $attributes) - { - if (!$this->subclassField) { - return $this->newInstance(); - } - - return new $attributes[$this->subclassField]; - } - - - /** - * - * instead of using $this->newInstance(), call - * newInstance() on the object from mapData - * - * @param bool $excludeDeleted - * - * @return \Illuminate\Database\Eloquent\Builder|static - */ - public function newQuery($excludeDeleted = true) - { - // If using Laravel 4.0.x then use the following commented version of this command - // $builder = new Builder($this->newBaseQueryBuilder()); - // newEloquentBuilder() was added in 4.1 - $builder = $this->newEloquentBuilder($this->newBaseQueryBuilder()); - - // Once Firefly has the query builders, it will set the model instances so the - // builder can easily access any information it may need from the model - // while it is constructing and executing various queries against it. - $builder->setModel($this)->with($this->with); - - if ($excludeDeleted && $this->softDelete) { - $builder->whereNull($this->getQualifiedDeletedAtColumn()); - } - - if ($this->subclassField && $this->isSubclass()) { - $builder->where($this->subclassField, '=', get_class($this)); - } - - return $builder; - } - - /** - * @return bool - */ - public function isSubclass() - { - return $this->isSubclass; - } - - /** - * ensure that the subclass field is assigned on save - * - * @param array $rules - * @param array $customMessages - * @param array $options - * @param callable $beforeSave - * @param callable $afterSave - * - * @return bool - */ - public function save( - array $rules = [], - array $customMessages = [], - array $options = [], - \Closure $beforeSave = null, - \Closure $afterSave = null - ) { - if ($this->subclassField) { - $this->attributes[$this->subclassField] = get_class($this); - } - - return parent::save($rules, $customMessages, $options, $beforeSave, $afterSave); - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Exception/FireflyException.php b/app/lib/Firefly/Exception/FireflyException.php deleted file mode 100644 index eb0f038fa3..0000000000 --- a/app/lib/Firefly/Exception/FireflyException.php +++ /dev/null @@ -1,14 +0,0 @@ - 'Amount (min)', - 'amount_max' => 'Amount (max)', - 'match' => 'Matches on', - 'repeat_freq' => 'Repetition', - 'account_from_id' => 'Account from', - 'account_to_id' => 'Account to', - 'account_id' => 'Asset account' - ]; - - return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name)); - - } - - /** - * Return buttons for update/validate/return. - * - * @param $type - * @param $name - */ - public static function ffOptionsList($type, $name) - { - $previousValue = \Input::old('post_submit_action'); - $previousValue = is_null($previousValue) ? 'store' : $previousValue; - /* - * Store. - */ - $store = ''; - switch ($type) { - case 'create': - $store = '
'; - $store .= '
'; - break; - case 'update': - $store = '
'; - $store .= '
'; - break; - default: - throw new FireflyException('Cannot create ffOptionsList for option (store) ' . $type); - break; - } - - /* - * validate is always the same: - */ - $validate = '
'; - - /* - * Store & return: - */ - switch ($type) { - case 'create': - $return = '
'; - break; - case 'update': - $return = '
'; - break; - default: - throw new FireflyException('Cannot create ffOptionsList for option (store+return) ' . $type); - break; - } - return $store . $validate . $return; - } - - /** - * @param $type - * @param $name - * @param null $value - * @param array $options - * @param array $list - * - * @return string - * @throws FireflyException - */ - public static function ffInput($type, $name, $value = null, array $options = array(), $list = []) - { - /* - * add some defaults to this method: - */ - $options['class'] = 'form-control'; - $options['id'] = 'ffInput_' . $name; - $options['autocomplete'] = 'off'; - $label = self::label($name, $options); - /* - * Make label and placeholder look nice. - */ - $options['placeholder'] = ucfirst($name); - - /* - * Get pre filled value: - */ - if (\Session::has('prefilled')) { - $preFilled = \Session::get('preFilled'); - $value = isset($prefilled[$name]) && is_null($value) ? $prefilled[$name] : $value; - } - - /* - * Get the value. - */ - if (!is_null(\Input::old($name))) { - /* - * Old value overrules $value. - */ - $value = \Input::old($name); - } - - /* - * Get errors, warnings and successes from session: - */ - /** @var MessageBag $errors */ - $errors = \Session::get('errors'); - - /** @var MessageBag $warnings */ - $warnings = \Session::get('warnings'); - - /** @var MessageBag $successes */ - $successes = \Session::get('successes'); - - - /* - * If errors, add some more classes. - */ - switch (true) { - case (!is_null($errors) && $errors->has($name)): - $classes = 'form-group has-error has-feedback'; - break; - case (!is_null($warnings) && $warnings->has($name)): - $classes = 'form-group has-warning has-feedback'; - break; - case (!is_null($successes) && $successes->has($name)): - $classes = 'form-group has-success has-feedback'; - break; - default: - $classes = 'form-group'; - break; - } - - /* - * Add some HTML. - */ - $html = '
'; - $html .= ''; - $html .= '
'; - - - /* - * Switch input type: - */ - unset($options['label']); - switch ($type) { - case 'text': - $html .= \Form::input('text', $name, $value, $options); - break; - case 'amount': - $html .= '
'; - $html .= \Form::input('number', $name, $value, $options); - $html .= '
'; - break; - case 'number': - $html .= \Form::input('number', $name, $value, $options); - break; - case 'checkbox': - $checked = $options['checked']; - unset($options['checked'], $options['placeholder'], $options['autocomplete'], $options['class']); - $html .= '
'; - - - break; - case 'date': - $html .= \Form::input('date', $name, $value, $options); - break; - case 'select': - $html .= \Form::select($name, $list, $value, $options); - break; - default: - throw new FireflyException('Cannot handle type "' . $type . '" in FFFormBuilder.'); - break; - } - - /* - * If errors, respond to them: - */ - - if (!is_null($errors)) { - if ($errors->has($name)) { - $html .= ''; - $html .= '

' . e($errors->first($name)) . '

'; - } - } - unset($errors); - /* - * If warnings, respond to them: - */ - - if (!is_null($warnings)) { - if ($warnings->has($name)) { - $html .= ''; - $html .= '

' . e($warnings->first($name)) . '

'; - } - } - unset($warnings); - - /* - * If successes, respond to them: - */ - - if (!is_null($successes)) { - if ($successes->has($name)) { - $html .= ''; - $html .= '

' . e($successes->first($name)) . '

'; - } - } - unset($successes); - - $html .= '
'; - $html .= '
'; - - return $html; - - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/Account.php b/app/lib/Firefly/Helper/Controllers/Account.php deleted file mode 100644 index 93dd3b12d7..0000000000 --- a/app/lib/Firefly/Helper/Controllers/Account.php +++ /dev/null @@ -1,154 +0,0 @@ -accountIs($account) - ->leftJoin( - 'transaction_types', 'transaction_types.id', '=', - 'transaction_journals.transaction_type_id' - ) - ->where('transaction_types.type', 'Opening balance') - ->first(['transaction_journals.*']); - } - - /** - * 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, Firefly removes $item and continues like nothing ever happened. This will however, - * mess up some statisics but it's decided everybody should learn to live with that. - * - * Firefly might be needing some cleanup routine in the future. - * - * For now, Firefly simply warns 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 = [ - 'accounts' => [] - ]; - $items = []; - - // build a query: - $query = \TransactionJournal::withRelevantData() - ->defaultSorting() - ->accountIs($account) - ->after($start) - ->before($end); - // filter some: - switch (\Input::get('type')) { - case 'transactions': - $query->transactionTypes(['Deposit', 'Withdrawal']); - break; - case 'transfers': - $query->transactionTypes(['Transfer']); - break; - } - - switch (\Input::get('show')) { - case 'expenses': - case 'out': - $query->lessThan(0); - break; - case 'income': - case 'in': - $query->moreThan(0); - break; - } - - - // build paginator: - $totalItems = $query->count(); - $page = max(1, intval(\Input::get('page'))); - $skip = ($page - 1) * $perPage; - $result = $query->skip($skip)->take($perPage)->get(['transaction_journals.*']); - - - // get the relevant budgets, categories and accounts from this list: - /** @var $item \TransactionJournal */ - foreach ($result as $index => $item) { - - foreach ($item->components as $component) { - $stats[$component->class][$component->id] = $component; - } - - if (count($item->transactions) < 2) { - \Session::flash('warning', 'Some transactions are incomplete; they will not be shown.'); - unset($result[$index]); - continue; - } - $items[] = $item; - $fromAccount = $item->transactions[0]->account; - $toAccount = $item->transactions[1]->account; - $stats['accounts'][$fromAccount->id] = $fromAccount; - $stats['accounts'][$toAccount->id] = $toAccount; - } - $paginator = \Paginator::make($items, $totalItems, $perPage); - unset($result, $page, $item, $fromAccount, $toAccount); - - - // statistics (transactions) - $trIn = floatval( - \Transaction::before($end)->after($start)->accountIs($account)->moreThan(0) - ->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount') - ); - $trOut = floatval( - \Transaction::before($end)->after($start)->accountIs($account)->lessThan(0) - ->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount') - ); - $trDiff = $trIn + $trOut; - - // statistics (transfers) - $trfIn = floatval( - \Transaction::before($end)->after($start)->accountIs($account)->moreThan(0) - ->transactionTypes(['Transfer'])->sum('transactions.amount') - ); - $trfOut = floatval( - \Transaction::before($end)->after($start)->accountIs($account)->lessThan(0) - ->transactionTypes(['Transfer'])->sum('transactions.amount') - ); - $trfDiff = $trfIn + $trfOut; - - $stats['period'] = [ - 'in' => $trIn, - 'out' => $trOut, - 'diff' => $trDiff, - 't_in' => $trfIn, - 't_out' => $trfOut, - 't_diff' => $trfDiff - - ]; - - $return = [ - 'journals' => $paginator, - 'statistics' => $stats - ]; - - return $return; - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/AccountInterface.php b/app/lib/Firefly/Helper/Controllers/AccountInterface.php deleted file mode 100644 index 4c2e378845..0000000000 --- a/app/lib/Firefly/Helper/Controllers/AccountInterface.php +++ /dev/null @@ -1,30 +0,0 @@ -limits as $limit) { - - /** @var \LimitRepetition $repetition */ - foreach ($limit->limitrepetitions as $repetition) { - $repetition->left = $repetition->leftInRepetition(); - $periodOrder = $repetition->periodOrder(); - $period = $repetition->periodShow(); - if (!isset($return[$periodOrder])) { - - $return[$periodOrder] = [ - 'date' => $period, - 'start' => $repetition->startdate, - 'end' => $repetition->enddate, - 'budget_id' => $budget->id, - 'limitrepetitions' => [$repetition] - ]; - } else { - $return[$periodOrder]['limitrepetitions'][] = $repetition; - } - - } - } - } - krsort($return); - - return $return; - } - - /** - * Get a repetition (complex because of user check) - * and then get the transactions in it. - * @param $repetitionId - * - * @return array - */ - public function organizeRepetition(\LimitRepetition $repetition) - { - $result = []; - // get transactions: - $set = $repetition->limit->budget - ->transactionjournals() - ->withRelevantData() - ->transactionTypes(['Withdrawal']) - ->after($repetition->startdate) - ->before($repetition->enddate) - ->defaultSorting() - ->get(['transaction_journals.*']); - - $result[0] = [ - 'date' => $repetition->periodShow(), - 'limit' => $repetition->limit, - 'limitrepetition' => $repetition, - 'journals' => $set, - 'paginated' => false - ]; - - return $result; - } - - /** - * - * - * @param \Budget $budget - * @param bool $useSessionDates - * - * @return array|mixed - * @throws \Firefly\Exception\FireflyException - */ - public function organizeRepetitions(\Budget $budget, $useSessionDates = false) - { - $sessionStart = \Session::get('start'); - $sessionEnd = \Session::get('end'); - - $result = []; - $inRepetition = []; - - // get the limits: - if ($useSessionDates) { - $limits = $budget->limits()->where('startdate', '>=', $sessionStart->format('Y-m-d'))->where( - 'startdate', '<=', $sessionEnd->format('Y-m-d') - )->get(); - } else { - $limits = $budget->limits; - } - - /** @var \Limit $limit */ - foreach ($limits as $limit) { - foreach ($limit->limitrepetitions as $repetition) { - $order = $repetition->periodOrder(); - $result[$order] = [ - 'date' => $repetition->periodShow(), - 'limitrepetition' => $repetition, - 'limit' => $limit, - 'journals' => [], - 'paginated' => false - ]; - $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; - } - $result[$order]['journals'] = $transactions; - } - - } - if ($useSessionDates === false) { - $query = $budget->transactionjournals()->withRelevantData()->defaultSorting(); - if (count($inRepetition) > 0) { - $query->whereNotIn('transaction_journals.id', $inRepetition); - } - - // build paginator: - $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(); - - // stupid paginator! - $items = []; - /** @var $item \TransactionJournal */ - 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]; - } - krsort($result); - - return $result; - } - - /** - * @param \Budget $budget - * - * @return mixed|void - */ - public function outsideRepetitions(\Budget $budget) - { - $inRepetitions = []; - foreach ($budget->limits as $limit) { - foreach ($limit->limitrepetitions as $repetition) { - $set = $budget->transactionjournals() - ->transactionTypes(['Withdrawal']) - ->after($repetition->startdate) - ->before($repetition->enddate) - ->defaultSorting() - ->get(['transaction_journals.id']); - foreach ($set as $item) { - $inRepetitions[] = $item->id; - } - } - - } - - $query = $budget->transactionjournals() - ->withRelevantData() - ->whereNotIn('transaction_journals.id', $inRepetitions) - ->defaultSorting(); - - // build paginator: - $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(); - - // stupid paginator! - $items = []; - /** @var $item \TransactionJournal */ - foreach ($set as $item) { - $items[] = $item; - } - $paginator = \Paginator::make($items, $totalItems, $perPage); - $result = [0 => [ - 'date' => 'Not in an envelope', - 'limit' => null, - 'paginated' => true, - 'journals' => $paginator - ]]; - - return $result; - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/BudgetInterface.php b/app/lib/Firefly/Helper/Controllers/BudgetInterface.php deleted file mode 100644 index 8fc25c10f8..0000000000 --- a/app/lib/Firefly/Helper/Controllers/BudgetInterface.php +++ /dev/null @@ -1,44 +0,0 @@ -transactionjournals()->with( - ['transactions', 'transactions.account', 'transactiontype', 'components'] - )->orderBy('date', 'DESC')->orderBy('id', 'DESC')->before($end)->after($start)->get(); - - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/CategoryInterface.php b/app/lib/Firefly/Helper/Controllers/CategoryInterface.php deleted file mode 100644 index 6e95583bd7..0000000000 --- a/app/lib/Firefly/Helper/Controllers/CategoryInterface.php +++ /dev/null @@ -1,25 +0,0 @@ - $account->name, - 'id' => $account->id, - 'type' => 'spline', - 'pointStart' => $start->timestamp * 1000, - 'pointInterval' => 24 * 3600 * 1000, // one day - 'data' => [] - ]; - - while ($current <= $end) { - if ($current > $today) { - $return['data'][] = $account->predict(clone $current); - } else { - $return['data'][] = $account->balance(clone $current); - } - - $current->addDay(); - } - - return $return; - } - - /** - * @param \Account $account - * @param Carbon $date - * - * @return array - */ - public function accountDailySummary(\Account $account, Carbon $date) - { - $result = [ - 'rows' => [], - 'sum' => 0 - ]; - if ($account) { - // get journals in range: - $journals = \Auth::user()->transactionjournals()->with( - [ - 'transactions', - 'transactions.account', - 'transactioncurrency', - 'transactiontype' - ] - ) - ->distinct() - ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') - ->where('transactions.account_id', $account->id) - ->where('transaction_journals.date', $date->format('Y-m-d')) - ->orderBy('transaction_journals.date', 'DESC') - ->orderBy('transaction_journals.id', 'DESC') - ->get(['transaction_journals.*']); - - // loop all journals: - foreach ($journals as $journal) { - foreach ($journal->transactions as $transaction) { - $name = $transaction->account->name; - if ($transaction->account->id != $account->id) { - if (!isset($result['rows'][$name])) { - $result['rows'][$name] = [ - 'name' => $name, - 'id' => $transaction->account->id, - 'amount' => floatval($transaction->amount) - ]; - } else { - $result['rows'][$name]['amount'] += floatval($transaction->amount); - } - $result['sum'] += floatval($transaction->amount); - } - } - } - } - - return $result; - - } - - /** - * @param Carbon $start - * @param Carbon $end - * - * @return array - * @throws \Firefly\Exception\FireflyException - */ - public function categories(Carbon $start, Carbon $end) - { - - $result = []; - // grab all transaction journals in this period: - $journals = \TransactionJournal:: - with( - ['components', 'transactions' => function ($q) { - $q->where('amount', '>', 0); - }] - ) - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where('transaction_types.type', 'Withdrawal') - ->after($start)->before($end) - ->where('completed', 1) - ->get(['transaction_journals.*']); - foreach ($journals as $journal) { - // has to be one: - - if (!isset($journal->transactions[0])) { - throw new FireflyException('Journal #' . $journal->id . ' has ' . count($journal->transactions) - . ' transactions!'); - } - $transaction = $journal->transactions[0]; - $amount = floatval($transaction->amount); - - // get budget from journal: - $category = $journal->categories()->first(); - $categoryName = is_null($category) ? '(no category)' : $category->name; - - $result[$categoryName] = isset($result[$categoryName]) ? $result[$categoryName] + floatval($amount) - : $amount; - - } - unset($journal, $transaction, $category, $amount); - - // sort - arsort($result); - $chartData = []; - foreach ($result as $name => $value) { - $chartData[] = [$name, $value]; - } - - - return $chartData; - } - - /** - * @param \Category $category - * @param $range - * @param Carbon $start - * @param Carbon $end - * - * @return array - * @throws \Firefly\Exception\FireflyException - */ - public function categoryShowChart(\Category $category, $range, Carbon $start, Carbon $end) - { - $data = ['name' => $category->name . ' per ' . $range, 'data' => []]; - // go back twelve periods. Skip if empty. - $beginning = clone $start; - switch ($range) { - default: - throw new FireflyException('No beginning for range ' . $range); - break; - case '1D': - $beginning->subDays(12); - break; - case '1W': - $beginning->subWeeks(12); - break; - case '1M': - $beginning->subYear(); - break; - case '3M': - $beginning->subYears(3); - break; - case '6M': - $beginning->subYears(6); - break; - case 'custom': - $diff = $start->diff($end); - $days = $diff->days; - $beginning->subDays(12 * $days); - break; - } - - // loop over the periods: - while ($beginning <= $start) { - // increment currentEnd to fit beginning: - $currentEnd = clone $beginning; - // increase beginning for next round: - switch ($range) { - default: - throw new FireflyException('No currentEnd incremental for range ' . $range); - break; - case '1D': - break; - case '1W': - $currentEnd->addWeek()->subDay(); - break; - case '1M': - $currentEnd->addMonth()->subDay(); - break; - case '3M': - $currentEnd->addMonths(3)->subDay(); - break; - case '6M': - $currentEnd->addMonths(6)->subDay(); - break; - case 'custom': - $diff = $start->diff($end); - $days = $diff->days; - $days = $days == 1 ? 2 : $days; - $currentEnd->addDays($days)->subDay(); - break; - } - - - // now format the current range: - $title = ''; - switch ($range) { - default: - throw new FireflyException('No date formats for frequency "' . $range . '"!'); - break; - case '1D': - $title = $beginning->format('j F Y'); - break; - case '1W': - $title = $beginning->format('\W\e\e\k W, Y'); - break; - case '1M': - $title = $beginning->format('F Y'); - break; - case '3M': - case '6M': - $title = $beginning->format('M Y') . ' - ' . $currentEnd->format('M Y'); - break; - case 'custom': - $title = $beginning->format('d-m-Y') . ' - ' . $currentEnd->format('d-m-Y'); - break; - case 'yearly': -// return $this->startdate->format('Y'); - break; - } - - - // get sum for current range: - $journals = \TransactionJournal:: - with( - ['transactions' => function ($q) { - $q->where('amount', '>', 0); - }] - ) - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->where('transaction_types.type', 'Withdrawal') - ->leftJoin( - 'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=', - 'transaction_journals.id' - ) - ->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id') - ->where('components.id', '=', $category->id) - //->leftJoin() - ->after($beginning)->before($currentEnd) - ->where('completed', 1) - ->get(['transaction_journals.*']); - $currentSum = 0; - foreach ($journals as $journal) { - if (!isset($journal->transactions[0])) { - throw new FireflyException('Journal #' . $journal->id . ' has ' . count($journal->transactions) - . ' transactions!'); - } - $transaction = $journal->transactions[0]; - $amount = floatval($transaction->amount); - $currentSum += $amount; - - } - $data['data'][] = [$title, $currentSum]; - - // increase beginning for next round: - switch ($range) { - default: - throw new FireflyException('No incremental for range ' . $range); - break; - case '1D': - $beginning->addDay(); - break; - case '1W': - $beginning->addWeek(); - break; - case '1M': - $beginning->addMonth(); - break; - case '3M': - $beginning->addMonths(3); - break; - case '6M': - $beginning->addMonths(6); - break; - case 'custom': - $diff = $start->diff($end); - $days = $diff->days; - - $beginning->addDays($days); - break; - - } - } - - return $data; - - - } - - /** - * @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; - } - - /** - * Firefly checks how much money has been spend on the limitrepetition (aka: the current envelope) in - * the period denoted. Aka, the user has a certain amount of money in an envelope and wishes to know how - * much he has spent between the dates entered. This date range 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') - ); - } - - -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/ChartInterface.php b/app/lib/Firefly/Helper/Controllers/ChartInterface.php deleted file mode 100644 index 1706fde96f..0000000000 --- a/app/lib/Firefly/Helper/Controllers/ChartInterface.php +++ /dev/null @@ -1,108 +0,0 @@ - intval(\Input::get('start')), - 'length' => $length, - 'draw' => intval(\Input::get('draw')), - ]; - - - /* - * Columns: - */ - if (!is_null(\Input::get('columns')) && is_array(\Input::get('columns'))) { - foreach (\Input::get('columns') as $column) { - $parameters['columns'][] = [ - 'data' => $column['data'], - 'name' => $column['name'], - 'searchable' => $column['searchable'] == 'true' ? true : false, - 'orderable' => $column['orderable'] == 'true' ? true : false, - 'search' => [ - 'value' => $column['search']['value'], - 'regex' => $column['search']['regex'] == 'true' ? true : false, - ] - ]; - } - } - - - /* - * Sorting. - */ - $parameters['orderOnAccount'] = false; - if (!is_null(\Input::get('order')) && is_array(\Input::get('order'))) { - foreach (\Input::get('order') as $order) { - $columnIndex = intval($order['column']); - $columnName = $parameters['columns'][$columnIndex]['name']; - $parameters['order'][] = [ - 'name' => $columnName, - 'dir' => strtoupper($order['dir']) - ]; - if ($columnName == 'to' || $columnName == 'from') { - $parameters['orderOnAccount'] = true; - } - } - } - /* - * Search parameters: - */ - $parameters['search'] = [ - 'value' => '', - 'regex' => false - ]; - if (!is_null(\Input::get('search')) && is_array(\Input::get('search'))) { - $search = \Input::get('search'); - $parameters['search'] = [ - 'value' => $search['value'], - 'regex' => $search['regex'] == 'true' ? true : false - ]; - } - return $parameters; - } - - /** - * Do some sorting, counting and ordering on the query and return a nicely formatted array - * that can be used by the DataTables JQuery plugin. - * - * @param array $parameters - * @param Builder $query - * - * @return array - */ - public function journalDataset(array $parameters, Builder $query) - { - /* - * Count query: - */ - $count = $query->count(); - - /* - * Update the selection: - */ - - $query->take($parameters['length']); - if ($parameters['start'] > 0) { - $query->skip($parameters['start']); - } - - /* - * Input search parameters: - */ - $filtered = $count; - if (strlen($parameters['search']['value']) > 0) { - $query->where('transaction_journals.description', 'LIKE', '%' . e($parameters['search']['value']) . '%'); - $filtered = $query->count(); - } - - - /* - * Build return array: - */ - $data = [ - 'draw' => $parameters['draw'], - 'recordsTotal' => $count, - 'recordsFiltered' => $filtered, - 'data' => [], - - ]; - - /* - * Get paginated result set: - */ - if ($parameters['orderOnAccount'] === true) { - /** @var Collection $set */ - $set = $query->get( - [ - 'transaction_journals.*', - 't1.amount', - 't1.account_id AS from_id', - 'a1.name AS from', - 't2.account_id AS to_id', - 'a2.name AS to', - ] - ); - } else { - /** @var Collection $set */ - $set = $query->get( - [ - 'transaction_journals.*', - 'transactions.amount', - ] - ); - } - - /* - * Loop set and create entries to return. - */ - /** @var \TransactionJournal $entry */ - foreach ($set as $entry) { - $from = $entry->transactions[0]->account; - $to = $entry->transactions[1]->account; - $budget = $entry->budgets()->first(); - $category = $entry->categories()->first(); - $recurring = $entry->recurringTransaction()->first(); - $arr = [ - 'date' => $entry->date->format('j F Y'), - 'description' => [ - 'description' => $entry->description, - 'url' => route('transactions.show', $entry->id) - ], - 'amount' => floatval($entry->amount), - 'from' => ['name' => $from->name, 'url' => route('accounts.show', $from->id)], - 'to' => ['name' => $to->name, 'url' => route('accounts.show', $to->id)], - 'components' => [ - 'budget_id' => 0, - 'budget_url' => '', - 'budget_name' => '', - 'category_id' => 0, - 'category_url' => '', - 'category_name' => '' - ], - 'id' => [ - 'edit' => route('transactions.edit', $entry->id), - 'delete' => route('transactions.delete', $entry->id) - ] - ]; - if ($budget) { - $arr['components']['budget_id'] = $budget->id; - $arr['components']['budget_name'] = $budget->name; - $arr['components']['budget_url'] = route('budgets.show', $budget->id); - } - if ($category) { - $arr['components']['category_id'] = $category->id; - $arr['components']['category_name'] = $category->name; - $arr['components']['category_url'] = route('categories.show', $category->id); - } - if ($recurring) { - $arr['components']['recurring_id'] = $recurring->id; - $arr['components']['recurring_name'] = e($recurring->name); - $arr['components']['recurring_url'] = route('recurring.show', $recurring->id); - } - - $data['data'][] = $arr; - - } - return $data; - } - - /** - * Builds most of the query required to grab transaction journals from the database. - * This is useful because all three pages showing different kinds of transactions use - * the exact same query with only slight differences. - * - * @param array $parameters - * - * @return Builder - */ - public function journalQuery(array $parameters) - { - /* - * We need the following vars to fine tune the query: - */ - if ($parameters['amount'] == 'negative') { - $operator = '<'; - $operatorNegated = '>'; - $function = 'lessThan'; - } else { - $operator = '>'; - $operatorNegated = '<'; - $function = 'moreThan'; - } - - /* - * Build query: - */ - $query = \TransactionJournal::transactionTypes($parameters['transactionTypes'])->withRelevantData(); - $query->where('user_id', \Auth::user()->id); - $query->where('completed', 1); - /* - * This is complex. Join `transactions` twice, once for the "to" account and once for the - * "from" account. Then get the amount from one of these (depends on type). - * - * Only need to do this when there's a sort order for "from" or "to". - * - * Also need the table prefix for this to work. - */ - if ($parameters['orderOnAccount'] === true) { - $connection = \Config::get('database.default'); - $prefix = \Config::get('database.connections.' . $connection . '.prefix'); - // left join first table for "from" account: - $query->leftJoin( - 'transactions AS ' . $prefix . 't1', function ($join) use ($operator) { - $join->on('t1.transaction_journal_id', '=', 'transaction_journals.id') - ->on('t1.amount', $operator, \DB::Raw(0)); - } - ); - // left join second table for "to" account: - $query->leftJoin( - 'transactions AS ' . $prefix . 't2', function ($join) use ($operatorNegated) { - $join->on('t2.transaction_journal_id', '=', 'transaction_journals.id') - ->on('t2.amount', $operatorNegated, \DB::Raw(0)); - } - ); - - // also join accounts twice to get the account's name, which we need for sorting. - $query->leftJoin('accounts as ' . $prefix . 'a1', 'a1.id', '=', 't1.account_id'); - $query->leftJoin('accounts as ' . $prefix . 'a2', 'a2.id', '=', 't2.account_id'); - } else { - // less complex - $query->$function(0); - } - - /* - * Add sort parameters to query: - */ - if (isset($parameters['order']) && count($parameters['order']) > 0) { - foreach ($parameters['order'] as $order) { - $query->orderBy($order['name'], $order['dir']); - } - } else { - $query->defaultSorting(); - } - return $query; - } - - /** - * Do some sorting, counting and ordering on the query and return a nicely formatted array - * that can be used by the DataTables JQuery plugin. - * - * @param array $parameters - * @param Builder $query - * - * @return array - */ - public function recurringTransactionsDataset(array $parameters, Builder $query) - { - /* - * Count query: - */ - $count = $query->count(); - - /* - * Update the selection: - */ - - $query->take($parameters['length']); - if ($parameters['start'] > 0) { - $query->skip($parameters['start']); - } - - /* - * Input search parameters: - */ - $filtered = $count; - if (strlen($parameters['search']['value']) > 0) { - $query->where('recurring_transactions.description', 'LIKE', '%' . e($parameters['search']['value']) . '%'); - $filtered = $query->count(); - } - - - /* - * Build return array: - */ - $data = [ - 'draw' => $parameters['draw'], - 'recordsTotal' => $count, - 'recordsFiltered' => $filtered, - 'data' => [], - - ]; - - /* - * Get paginated result set: - */ - /** @var Collection $set */ - $set = $query->get( - [ - 'recurring_transactions.*', - ] - ); - - /* - * Loop set and create entries to return. - */ - foreach ($set as $entry) { - $set = [ - - 'name' => ['name' => $entry->name, 'url' => route('recurring.show', $entry->id)], - 'match' => explode(' ', $entry->match), - 'amount_max' => floatval($entry->amount_max), - 'amount_min' => floatval($entry->amount_min), - 'date' => $entry->date->format('j F Y'), - 'active' => intval($entry->active), - 'automatch' => intval($entry->automatch), - 'repeat_freq' => $entry->repeat_freq, - 'id' => [ - 'edit' => route('recurring.edit', $entry->id), - 'delete' => route('recurring.delete', $entry->id) - ] - ]; - if (intval($entry->skip) > 0) { - $set['repeat_freq'] = $entry->repeat_freq . ' (skip ' . $entry->skip . ')'; - } - $data['data'][] = $set; - - - } - return $data; - } - - /** - * Create a query that will pick up all recurring transactions from the database. - * - * @param array $parameters - * - * @return Builder - */ - public function recurringTransactionsQuery(array $parameters) - { - $query = \RecurringTransaction::where('user_id', \Auth::user()->id); - - if (isset($parameters['order']) && count($parameters['order']) > 0) { - foreach ($parameters['order'] as $order) { - $query->orderBy($order['name'], $order['dir']); - } - } else { - $query->orderBy('name', 'ASC'); - } - return $query; - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/JsonInterface.php b/app/lib/Firefly/Helper/Controllers/JsonInterface.php deleted file mode 100644 index 4e05d2f02e..0000000000 --- a/app/lib/Firefly/Helper/Controllers/JsonInterface.php +++ /dev/null @@ -1,64 +0,0 @@ -add('name', 'The name should not be this short.'); - } - if (strlen($data['name']) > 250) { - $errors->add('name', 'The name should not be this long.'); - } - if (! isset($data['id'])) { - $count = \Auth::user()->recurringtransactions()->whereName($data['name'])->count(); - } else { - $count = \Auth::user()->recurringtransactions()->whereName($data['name'])->where('id', '!=', $data['id'])->count(); - } - if ($count > 0) { - $errors->add('name', 'A recurring transaction with this name already exists.'); - } - if (count($errors->get('name')) == 0) { - $successes->add('name', 'OK!'); - } - - /* - * Match - */ - if (count(explode(',', $data['match'])) > 10) { - $warnings->add('match', 'This many matches is pretty pointless'); - } - if (strlen($data['match']) == 0) { - $errors->add('match', 'Cannot match on nothing.'); - } - if (count($errors->get('match')) == 0) { - $successes->add('match', 'OK!'); - } - - /* - * Amount - */ - if (floatval($data['amount_max']) == 0 && floatval($data['amount_min']) == 0) { - $errors->add('amount_min', 'Amount max and min cannot both be zero.'); - $errors->add('amount_max', 'Amount max and min cannot both be zero.'); - } - - if (floatval($data['amount_max']) < floatval($data['amount_min'])) { - $errors->add('amount_max', 'Amount max must be more than amount min.'); - } - - if (floatval($data['amount_min']) > floatval($data['amount_max'])) { - $errors->add('amount_max', 'Amount min must be less than amount max.'); - } - if (count($errors->get('amount_min')) == 0) { - $successes->add('amount_min', 'OK!'); - } - if (count($errors->get('amount_max')) == 0) { - $successes->add('amount_max', 'OK!'); - } - - - /* - * Date - */ - try { - $date = new Carbon($data['date']); - } catch (Exception $e) { - $errors->add('date', 'The date entered was invalid'); - } - if (strlen($data['date']) == 0) { - $errors->add('date', 'The date entered was invalid'); - } - if (!$errors->has('date')) { - $successes->add('date', 'OK!'); - } - - $successes->add('active', 'OK!'); - $successes->add('automatch', 'OK!'); - - if (intval($data['skip']) < 0) { - $errors->add('skip', 'Cannot be below zero.'); - } else if (intval($data['skip']) > 31) { - $errors->add('skip', 'Cannot be above 31.'); - } - if (count($errors->get('skip')) == 0) { - $successes->add('skip', 'OK!'); - } - - $set = \Config::get('firefly.budget_periods'); - if (!in_array($data['repeat_freq'], $set)) { - $errors->add('repeat_freq', 'Invalid value.'); - } - if (count($errors->get('repeat_freq')) == 0) { - $successes->add('repeat_freq', 'OK!'); - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/RecurringInterface.php b/app/lib/Firefly/Helper/Controllers/RecurringInterface.php deleted file mode 100644 index b14183201c..0000000000 --- a/app/lib/Firefly/Helper/Controllers/RecurringInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -transactionjournals()->withRelevantData()->where( - function ($q) use ($words) { - foreach ($words as $word) { - $q->orWhere('description', 'LIKE', '%' . e($word) . '%'); - } - } - )->get(); - } - - /** - * @param array $words - * - * @return Collection - */ - public function searchAccounts(array $words) - { - return \Auth::user()->accounts()->with('accounttype')->where( - function ($q) use ($words) { - foreach ($words as $word) { - $q->orWhere('name', 'LIKE', '%' . e($word) . '%'); - } - } - )->get(); - } - - /** - * @param array $words - * - * @return Collection - */ - public function searchCategories(array $words) - { - /** @var Collection $set */ - $set = \Auth::user()->categories()->get(); - $newSet = $set->filter( - function (\Category $c) use ($words) { - $found = 0; - foreach ($words as $word) { - if (!(strpos(strtolower($c->name), strtolower($word)) === false)) { - $found++; - } - } - return $found > 0; - } - ); - return $newSet; - } - - /** - * @param array $words - * - * @return Collection - */ - public function searchBudgets(array $words) - { - /** @var Collection $set */ - $set = \Auth::user()->budgets()->get(); - $newSet = $set->filter( - function (\Budget $b) use ($words) { - $found = 0; - foreach ($words as $word) { - if (!(strpos(strtolower($b->name), strtolower($word)) === false)) { - $found++; - } - } - return $found > 0; - } - ); - return $newSet; - } - - /** - * @param array $words - * - * @return Collection - */ - public function searchTags(array $words) - { - return new Collection; - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/SearchInterface.php b/app/lib/Firefly/Helper/Controllers/SearchInterface.php deleted file mode 100644 index 2af4e8918f..0000000000 --- a/app/lib/Firefly/Helper/Controllers/SearchInterface.php +++ /dev/null @@ -1,36 +0,0 @@ -_journals = $journals; - $this->_categories = $categories; - $this->_budgets = $budgets; - $this->_piggybanks = $piggybanks; - $this->_accounts = $accounts; - $this->overruleUser(\Auth::user()); - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - $this->_journals->overruleUser($user); - $this->_categories->overruleUser($user); - $this->_budgets->overruleUser($user); - $this->_piggybanks->overruleUser($user); - $this->_accounts->overruleUser($user); - return true; - } - - /** - * @param \TransactionJournal $journal - * @param array $data - * - * @return MessageBag|\TransactionJournal - */ - public function update(\TransactionJournal $journal, array $data) - { - /* - * Update the journal using the repository. - */ - $journal = $this->_journals->update($journal, $data); - - /* - * If invalid, return the message bag: - */ - if (!$journal->validate()) { - return $journal->errors(); - } - - /* - * find budget using repository - */ - - if (isset($data['budget_id'])) { - $budget = $this->_budgets->find($data['budget_id']); - } - - /* - * find category using repository - */ - $category = $this->_categories->firstOrCreate($data['category']); - - /* - * Find piggy bank using repository: - */ - $piggybank = null; - if (isset($data['piggybank_id'])) { - $piggybank = $this->_piggybanks->find($data['piggybank_id']); - } - - /* - * save accounts using repositories - * this depends on the kind of transaction and i've yet to fix this. - */ - - if (isset($data['account_id'])) { - $from = $this->_accounts->findAssetAccountById($data['account_id']); - } - if (isset($data['expense_account'])) { - $to = $this->_accounts->findExpenseAccountByName($data['expense_account']); - } - if (isset($data['revenue_account'])) { - $from = $this->_accounts->findRevenueAccountByName($data['revenue_account']); - $to = $this->_accounts->findAssetAccountById($data['account_id']); - } - if (isset($data['account_from_id'])) { - $from = $this->_accounts->findAssetAccountById($data['account_from_id']); - } - if (isset($data['account_to_id'])) { - $to = $this->_accounts->findAssetAccountById($data['account_to_id']); - } - - - /* - * Add a custom error when they are the same. - */ - if ($to->id == $from->id) { - $bag = new MessageBag; - $bag->add('account_from_id', 'The account from cannot be the same as the account to.'); - return $bag; - } - - /* - * Check if the transactions need new data: - */ - $transactions = $journal->transactions()->orderBy('amount', 'ASC')->get(); - /** @var \Transaction $transaction */ - foreach ($transactions as $index => $transaction) { - switch (true) { - case ($index == 0): // FROM account - $transaction->account()->associate($from); - $transaction->amount = floatval($data['amount']) * -1; - break; - case ($index == 1): // TO account. - $transaction->account()->associate($to); - $transaction->amount = floatval($data['amount']); - break; - } - $transaction->save(); - // either way, try to attach the piggy bank: - if (!is_null($piggybank)) { - if ($piggybank->account_id == $transaction->account_id) { - $transaction->piggybank()->associate($piggybank); - } - } - } - - /* - * Connect budget and category: - */ - $budgetids = !isset($budget) || (isset($budget) && is_null($budget)) ? [] : [$budget->id]; - $catids = is_null($category) ? [] : [$category->id]; - $components = array_merge($budgetids,$catids); - $journal->components()->sync($components); - $journal->save(); - - if (isset($data['return_journal']) && $data['return_journal'] == true) { - return $journal; - } - return $journal->errors(); - - } - - /** - * Returns messages about the validation. - * - * @param array $data - * @return array - * @throws FireflyException - */ - public function validate(array $data) - { - $errors = new MessageBag; - $warnings = new MessageBag; - $successes = new MessageBag; - - /* - * Description: - */ - if (strlen($data['description']) == 0) { - $errors->add('description', 'The description should not be this short.'); - } - if (strlen($data['description']) > 250) { - $errors->add('description', 'The description should not be this long.'); - } - - /* - * Amount - */ - if (floatval($data['amount']) <= 0) { - $errors->add('amount', 'The amount cannot be zero or less than zero.'); - } - if (floatval($data['amount']) > 10000) { - $warnings->add('amount', 'OK, but that\'s a lot of money dude.'); - } - - /* - * Date - */ - try { - $date = new Carbon($data['date']); - } catch (Exception $e) { - $errors->add('date', 'The date entered was invalid'); - } - if (strlen($data['date']) == 0) { - $errors->add('date', 'The date entered was invalid'); - } - if (!$errors->has('date')) { - $successes->add('date', 'OK!'); - } - - /* - * Category - */ - $category = $this->_categories->findByName($data['category']); - if (strlen($data['category']) == 0) { - $warnings->add('category', 'No category will be created.'); - } else { - if (is_null($category)) { - $warnings->add('category', 'Will have to be created.'); - } else { - $successes->add('category', 'OK!'); - } - } - - switch ($data['what']) { - default: - throw new FireflyException('Cannot validate a ' . $data['what']); - break; - case 'deposit': - /* - * Tests for deposit - */ - // asset account - $accountId = isset($data['account_id']) ? intval($data['account_id']) : 0; - $account = $this->_accounts->find($accountId); - if (is_null($account)) { - $errors->add('account_id', 'Cannot find this asset account.'); - } else { - $successes->add('account_id', 'OK!'); - } - - // revenue account: - if (strlen($data['revenue_account']) == 0) { - $warnings->add('revenue_account', 'Revenue account will be "cash".'); - } else { - $exp = $this->_accounts->findRevenueAccountByName($data['revenue_account'], false); - if (is_null($exp)) { - $warnings->add('revenue_account', 'Expense account will be created.'); - } else { - $successes->add('revenue_account', 'OK!'); - } - } - - break; - case 'transfer': - // account from - $accountId = isset($data['account_from_id']) ? intval($data['account_from_id']) : 0; - $account = $this->_accounts->find($accountId); - if (is_null($account)) { - $errors->add('account_from_id', 'Cannot find this asset account.'); - } else { - $successes->add('account_from_id', 'OK!'); - } - unset($accountId); - // account to - $accountId = isset($data['account_to_id']) ? intval($data['account_to_id']) : 0; - $account = $this->_accounts->find($accountId); - if (is_null($account)) { - $errors->add('account_to_id', 'Cannot find this asset account.'); - } else { - $successes->add('account_to_id', 'OK!'); - } - unset($accountId); - - // piggy bank - $piggybankId = isset($data['piggybank_id']) ? intval($data['piggybank_id']) : 0; - $piggybank = $this->_piggybanks->find($piggybankId); - if (is_null($piggybank)) { - $warnings->add('piggybank_id', 'No piggy bank will be modified.'); - } else { - $successes->add('piggybank_id', 'OK!'); - } - - break; - case 'withdrawal': - /* - * Tests for withdrawal - */ - // asset account - $accountId = isset($data['account_id']) ? intval($data['account_id']) : 0; - $account = $this->_accounts->find($accountId); - if (is_null($account)) { - $errors->add('account_id', 'Cannot find this asset account.'); - } else { - $successes->add('account_id', 'OK!'); - } - - // expense account - if (strlen($data['expense_account']) == 0) { - $warnings->add('expense_account', 'Expense account will be "cash".'); - } else { - $exp = $this->_accounts->findExpenseAccountByName($data['expense_account'], false); - if (is_null($exp)) { - $warnings->add('expense_account', 'Expense account will be created.'); - } else { - $successes->add('expense_account', 'OK!'); - } - } - - // budget - if (!isset($data['budget_id']) || (isset($data['budget_id']) && intval($data['budget_id']) == 0)) { - $warnings->add('budget_id', 'No budget selected.'); - } else { - $budget = $this->_budgets->find(intval($data['budget_id'])); - if (is_null($budget)) { - $errors->add('budget_id', 'This budget does not exist'); - } else { - $successes->add('budget_id', 'OK!'); - } - } - - break; - } - - if (count($errors->get('description')) == 0) { - $successes->add('description', 'OK!'); - } - - if (count($errors->get('amount')) == 0) { - $successes->add('amount', 'OK!'); - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - /* - * Tests for deposit - */ - /* - * Tests for transfer - */ - - } - - /** - * Store a full transaction journal and associated stuff - * - * @param array $data - * - * @return MessageBag|\TransactionJournal - * - * @SuppressWarnings(PHPMD.ShortVariable) - */ - public function store(array $data) - { - /* - * save journal using repository - */ - $journal = $this->_journals->store($data); - - /* - * If invalid, return the message bag: - */ - if (!$journal->validate()) { - return $journal->errors(); - } - - /* - * find budget using repository - */ - if (isset($data['budget_id'])) { - $budget = $this->_budgets->find($data['budget_id']); - } - - /* - * find category using repository - */ - $category = $this->_categories->firstOrCreate($data['category']); - - /* - * Find piggy bank using repository: - */ - $piggybank = null; - if (isset($data['piggybank_id'])) { - $piggybank = $this->_piggybanks->find($data['piggybank_id']); - } - - /* - * save accounts using repositories - * this depends on the kind of transaction and i've yet to fix this. - */ - if (isset($data['account_id'])) { - $from = $this->_accounts->findAssetAccountById($data['account_id']); - } - if (isset($data['expense_account'])) { - $to = $this->_accounts->findExpenseAccountByName($data['expense_account']); - - } - if (isset($data['revenue_account'])) { - $from = $this->_accounts->findRevenueAccountByName($data['revenue_account']); - $to = $this->_accounts->findAssetAccountById($data['account_id']); - } - if (isset($data['account_from_id'])) { - $from = $this->_accounts->findAssetAccountById($data['account_from_id']); - } - if (isset($data['account_to_id'])) { - $to = $this->_accounts->findAssetAccountById($data['account_to_id']); - } - - /* - * Add a custom error when they are the same. - */ - if ($to->id == $from->id) { - $bag = new MessageBag; - $bag->add('account_from_id', 'The account from cannot be the same as the account to.'); - return $bag; - } - - /* - * Save transactions using repository. We try to connect the (possibly existing) - * piggy bank to either transaction, knowing it will only work with one of them. - */ - /** @var \Transaction $one */ - $one = $this->_journals->saveTransaction($journal, $from, floatval($data['amount']) * -1); - $one->connectPiggybank($piggybank); - $two = $this->_journals->saveTransaction($journal, $to, floatval($data['amount'])); - $two->connectPiggybank($piggybank); - /* - * Count for $journal is zero? Then there were errors! - */ - if ($journal->transactions()->count() < 2) { - /* - * Join message bags and return them: - */ - $bag = $one->errors(); - $bag->merge($two->errors()); - return $bag; - } - - /* - * Connect budget, category and piggy bank: - */ - if (isset($budget) && !is_null($budget)) { - $journal->budgets()->save($budget); - } - if (!is_null($category)) { - $journal->categories()->save($category); - } - $journal->completed = true; - $journal->save(); - - /* - * Trigger recurring transaction event. - */ - \Event::fire('journals.store',[$journal]); - - if (isset($data['return_journal']) && $data['return_journal'] == true) { - return ['journal' => $journal, 'messagebag' => $journal->errors()]; - } - return $journal->errors(); - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Controllers/TransactionInterface.php b/app/lib/Firefly/Helper/Controllers/TransactionInterface.php deleted file mode 100644 index 0c481b1494..0000000000 --- a/app/lib/Firefly/Helper/Controllers/TransactionInterface.php +++ /dev/null @@ -1,48 +0,0 @@ -reset = $reset; - $user->forceSave(); - $email = $user->email; - $data = ['reset' => $reset]; - - \Mail::send( - ['emails.user.verify-html', 'emails.user.verify-text'], $data, function ($message) use ($email) { - $message->to($email, $email)->subject('Verify your e-mail address.'); - } - ); - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function sendPasswordMail(\User $user) - { - - $password = \Str::random(12); - $user->password = $password; - $user->reset = \Str::random(32); // new one. - $user->forceSave(); - $email = $user->email; - - - $data = ['password' => $password]; - \Mail::send( - ['emails.user.register-html', 'emails.user.register-text'], $data, function ($message) use ($email) { - $message->to($email, $email)->subject('Welcome to Firefly!'); - } - ); - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function sendResetVerification(\User $user) - { - $reset = \Str::random(32); - $user->reset = $reset; - $user->forceSave(); - $email = $user->email; - - $data = ['reset' => $reset]; - \Mail::send( - ['emails.user.remindme-html', 'emails.user.remindme-text'], $data, function ($message) use ($email) { - $message->to($email, $email)->subject('Forgot your password?'); - } - ); - - - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Email/EmailHelperInterface.php b/app/lib/Firefly/Helper/Email/EmailHelperInterface.php deleted file mode 100644 index 48a49d0d02..0000000000 --- a/app/lib/Firefly/Helper/Email/EmailHelperInterface.php +++ /dev/null @@ -1,34 +0,0 @@ -app->bind( - 'Firefly\Helper\Controllers\AccountInterface', - 'Firefly\Helper\Controllers\Account' - ); - $this->app->bind( - 'Firefly\Helper\Controllers\ChartInterface', - 'Firefly\Helper\Controllers\Chart' - ); - - $this->app->bind( - 'Firefly\Helper\Controllers\JsonInterface', - 'Firefly\Helper\Controllers\Json' - ); - - $this->app->bind( - 'Firefly\Helper\Controllers\RecurringInterface', - 'Firefly\Helper\Controllers\Recurring' - ); - - $this->app->bind( - 'Firefly\Helper\Controllers\SearchInterface', - 'Firefly\Helper\Controllers\Search' - ); - - $this->app->bind( - 'Firefly\Helper\Controllers\TransactionInterface', - 'Firefly\Helper\Controllers\Transaction' - ); - - $this->app->bind( - 'Firefly\Helper\Controllers\CategoryInterface', - 'Firefly\Helper\Controllers\Category' - ); - - $this->app->bind( - 'Firefly\Helper\Controllers\BudgetInterface', - 'Firefly\Helper\Controllers\Budget' - ); - - // mail: - $this->app->bind( - 'Firefly\Helper\Email\EmailHelperInterface', - 'Firefly\Helper\Email\EmailHelper' - ); - - // settings: - $this->app->bind( - 'Firefly\Helper\Preferences\PreferencesHelperInterface', - 'Firefly\Helper\Preferences\PreferencesHelper' - ); - // settings: - $this->app->bind( - 'Firefly\Helper\Toolkit\ToolkitInterface', - 'Firefly\Helper\Toolkit\Toolkit' - ); - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Preferences/PreferencesHelper.php b/app/lib/Firefly/Helper/Preferences/PreferencesHelper.php deleted file mode 100644 index e212fca757..0000000000 --- a/app/lib/Firefly/Helper/Preferences/PreferencesHelper.php +++ /dev/null @@ -1,58 +0,0 @@ -id)->where('name', $name)->first(); - if (is_null($default) && is_null($pref)) { - // return NULL - return null; - } - if (!is_null($pref)) { - return $pref; - } - if (!is_null($default) && is_null($pref)) { - // create preference, return that: - return $this->set($name, $default); - } - - return null; - - } - - /** - * @param $name - * @param $value - * - * @return mixed|\Preference - */ - public function set($name, $value) - { - $pref = \Preference::where('user_id', \Auth::user()->id)->where('name', $name)->first(); - if (is_null($pref)) { - $pref = new \Preference; - $pref->name = $name; - $pref->user()->associate(\Auth::user()); - - } - $pref->data = $value; - $pref->save(); - - - return $pref; - - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Preferences/PreferencesHelperInterface.php b/app/lib/Firefly/Helper/Preferences/PreferencesHelperInterface.php deleted file mode 100644 index cb6d279825..0000000000 --- a/app/lib/Firefly/Helper/Preferences/PreferencesHelperInterface.php +++ /dev/null @@ -1,29 +0,0 @@ -_getRange(); - #\Log::debug('Range is: ' . $range); - $start = \Session::has('start') ? \Session::get('start') : new Carbon; - - #\Log::debug('Session start is: ' . $start->format('Y-m-d')); - $end = \Session::has('end') ? \Session::get('end') : new Carbon; - #\Log::debug('Session end is : ' . $end->format('Y-m-d')); - - /* - * Force start date to at the start of the $range. - * Ie. the start of the week, month, year. - */ - $start = $this->_updateStartDate($range, $start); - #\Log::debug('After update, session start is: ' . $start->format('Y-m-d')); - - /* - * Force end date to at the END of the $range. Always based on $start. - * Ie. the END of the week, month, year. - */ - $end = $this->_updateEndDate($range, $start); - #\Log::debug('After update, session end is : ' . $end->format('Y-m-d')); - - /* - * get the name of the month, depending on the range. Purely for astetics - */ - $period = $this->_periodName($range, $start); - - /* - * Get the date for the previous and next period. - * Ie. next week, next month, etc. - */ - $prev = $this->_previous($range, clone $start); - $next = $this->_next($range, clone $start); - - /* - * Save everything in the session: - */ - \Session::put('start', $start); - \Session::put('end', $end); - \Session::put('range', $range); - \Session::put('period', $period); - \Session::put('prev', $this->_periodName($range, $prev)); - \Session::put('next', $this->_periodName($range, $next)); - return null; - - } - - /** - * - */ - public function checkImportJobs() - { - /* - * Get all jobs. - */ - /** @var \Importmap $importJob */ - $importJob = \Importmap::where('user_id', \Auth::user()->id) - ->where('totaljobs', '>', \DB::Raw('`jobsdone`')) - ->orderBy('created_at', 'DESC') - ->first(); - if (!is_null($importJob)) { - $diff = intval($importJob->totaljobs) - intval($importJob->jobsdone); - $date = new Carbon; - $today = new Carbon; - $date->addSeconds($diff); - \Session::put('job_pct', $importJob->pct()); - \Session::put('job_text', $date->diffForHumans()); - } else { - \Session::forget('job_pct'); - \Session::forget('job_text'); - } - } - - protected function _getRange() - { - if (!is_null(\Session::get('range'))) { - $range = \Session::get('range'); - } else { - /** @noinspection PhpUndefinedClassInspection */ - $preferences = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface'); - $viewRange = $preferences->get('viewRange', '1M'); - - // default range: - $range = $viewRange->data; - \Session::put('range', $range); - } - return $range; - - } - - /** - * @param $range - * @param Carbon $start - * - * @return Carbon - */ - protected function _updateStartDate($range, Carbon $start) - { - switch ($range) { - case '1D': - $start->startOfDay(); - break; - case '1W': - $start->startOfWeek(); - break; - case '1M': - $start->startOfMonth(); - break; - case '3M': - $start->firstOfQuarter(); - break; - case '6M': - if (intval($start->format('m')) >= 7) { - $start->startOfYear()->addMonths(6); - } else { - $start->startOfYear(); - } - break; - case '1Y': - $start->startOfYear(); - break; - } - - return $start; - - } - - /** - * @param $range - * @param Carbon $start - * @param Carbon $end - * - * @return Carbon - */ - protected function _updateEndDate($range, Carbon $start) - { - $end = clone $start; - switch ($range) { - default: - throw new FireflyException('_updateEndDate cannot handle $range ' . $range); - break; - case '1D': - $end->endOfDay(); - break; - case '1W': - $end->endOfWeek(); - break; - case '1M': - $end->endOfMonth(); - break; - case '3M': - $end->lastOfQuarter(); - break; - case '6M': - if (intval($start->format('m')) >= 7) { - $end->endOfYear(); - } else { - $end->startOfYear()->addMonths(6); - } - break; - case '1Y': - $end->endOfYear(); - break; - - } - - return $end; - } - - protected function _periodName($range, Carbon $date) - { - switch ($range) { - default: - throw new FireflyException('No _periodName() for range "' . $range . '"'); - break; - case '1D': - return $date->format('jS F Y'); - break; - case '1W': - return 'week ' . $date->format('W, Y'); - break; - case '1M': - return $date->format('F Y'); - break; - case '3M': - $month = intval($date->format('m')); - return 'Q' . ceil(($month / 12) * 4) . ' ' . $date->format('Y'); - break; - case '6M': - $month = intval($date->format('m')); - $half = ceil(($month / 12) * 2); - $halfName = $half == 1 ? 'first' : 'second'; - return $halfName . ' half of ' . $date->format('d-m-Y'); - break; - case '1Y': - return $date->format('Y'); - break; - - - } - } - - protected function _previous($range, Carbon $date) - { - switch ($range) { - default: - throw new FireflyException('Cannot do _previous() on ' . $range); - break; - case '1D': - $date->startOfDay()->subDay(); - break; - case '1W': - $date->startOfWeek()->subWeek(); - break; - case '1M': - $date->startOfMonth()->subMonth(); - break; - case '3M': - $date->firstOfQuarter()->subMonths(3)->firstOfQuarter(); - break; - case '6M': - $month = intval($date->format('m')); - if ($month <= 6) { - $date->startOfYear()->subMonths(6); - } else { - $date->startOfYear(); - } - break; - case '1Y': - $date->startOfYear()->subYear(); - break; - - } - return $date; - } - - protected function _next($range, Carbon $date) - { - switch ($range) { - case '1D': - $date->endOfDay()->addDay(); - break; - case '1W': - $date->endOfWeek()->addDay()->startOfWeek(); - break; - case '1M': - $date->endOfMonth()->addDay()->startOfMonth(); - break; - case '3M': - $date->lastOfQuarter()->addDay(); - break; - case '6M': - if (intval($date->format('m')) >= 7) { - $date->startOfYear()->addYear(); - } else { - $date->startOfYear()->addMonths(6); - } - break; - case '1Y': - $date->startOfYear()->addYear(); - break; - default: - throw new FireflyException('Cannot do _next() on ' . $range); - break; - } - return $date; - } - - public function next() - { - /* - * Get the start date and the range from the session - */ - $range = $this->_getRange(); - $start = \Session::get('start'); - - /* - * Add some period to $start. - */ - $next = $this->_next($range, clone $start); - - /* - * Save in session: - */ - \Session::put('start', $next); - return true; - } - - public function prev() - { - /* - * Get the start date and the range from the session - */ - $range = $this->_getRange(); - $start = \Session::get('start'); - - /* - * Substract some period to $start. - */ - $prev = $this->_previous($range, clone $start); - - /* - * Save in session: - */ - \Session::put('start', $prev); - return true; - } - - /** - * Takes any collection and tries to make a sensible select list compatible array of it. - * - * @param Collection $set - * @param null $titleField - * - * @return mixed - */ - public function makeSelectList(Collection $set, $titleField = null) - { - $selectList = []; - /** @var Model $entry */ - foreach ($set as $entry) { - $id = intval($entry->id); - $title = null; - if (is_null($titleField)) { - // try 'title' field. - if (isset($entry->title)) { - $title = $entry->title; - } - // try 'name' field - if (is_null($title)) { - $title = $entry->name; - } - - // try 'description' field - if (is_null($title)) { - $title = $entry->description; - } - } else { - $title = $entry->$titleField; - } - $selectList[$id] = $title; - } - return $selectList; - } - - /** - * @param string $start - * @param string $end - * @param int $steps - */ - public function colorRange($start, $end, $steps = 5) - { - if (strlen($start) != 6) { - throw new FireflyException('Start, ' . e($start) . ' should be a six character HTML colour.'); - } - if (strlen($end) != 6) { - throw new FireflyException('End, ' . e($end) . ' should be a six character HTML colour.'); - } - if ($steps < 1) { - throw new FireflyException('Steps must be > 1'); - } - - $start = '#' . $start; - $end = '#' . $end; - /* - * Split html colours. - */ - list($rs, $gs, $bs) = sscanf($start, "#%02x%02x%02x"); - list($re, $ge, $be) = sscanf($end, "#%02x%02x%02x"); - - $stepr = ($re - $rs) / $steps; - $stepg = ($ge - $gs) / $steps; - $stepb = ($be - $bs) / $steps; - - $return = []; - for ($i = 0; $i <= $steps; $i++) { - $cr = $rs + ($stepr * $i); - $cg = $gs + ($stepg * $i); - $cb = $bs + ($stepb * $i); - - $return[] = $this->rgb2html($cr, $cg, $cb); - } - - return $return; - } - - protected function rgb2html($r, $g = -1, $b = -1) - { - $r = dechex($r < 0 ? 0 : ($r > 255 ? 255 : $r)); - $g = dechex($g < 0 ? 0 : ($g > 255 ? 255 : $g)); - $b = dechex($b < 0 ? 0 : ($b > 255 ? 255 : $b)); - - $color = (strlen($r) < 2 ? '0' : '') . $r; - $color .= (strlen($g) < 2 ? '0' : '') . $g; - $color .= (strlen($b) < 2 ? '0' : '') . $b; - return '#' . $color; - } - - /** - * @param Carbon $currentEnd - * @param $repeatFreq - * @throws FireflyException - */ - public function endOfPeriod(Carbon $currentEnd, $repeatFreq) - { - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do getFunctionForRepeatFreq for $repeat_freq ' . $repeatFreq); - break; - case 'daily': - $currentEnd->addDay(); - break; - case 'weekly': - $currentEnd->addWeek()->subDay(); - break; - case 'monthly': - $currentEnd->addMonth()->subDay(); - break; - case 'quarterly': - $currentEnd->addMonths(3)->subDay(); - break; - case 'half-year': - $currentEnd->addMonths(6)->subDay(); - break; - case 'yearly': - $currentEnd->addYear()->subDay(); - break; - } - } - - /** - * @param Carbon $date - * @param $repeatFreq - * @param $skip - * @return Carbon - * @throws FireflyException - */ - public function addPeriod(Carbon $date, $repeatFreq, $skip) - { - $add = ($skip + 1); - switch ($repeatFreq) { - default: - throw new FireflyException('Cannot do getFunctionForRepeatFreq for $repeat_freq ' . $repeatFreq); - break; - case 'daily': - $date->addDays($add); - break; - case 'weekly': - $date->addWeeks($add); - break; - case 'monthly': - $date->addMonths($add); - break; - case 'quarterly': - $months = $add * 3; - $date->addMonths($months); - break; - case 'half-year': - $months = $add * 6; - $date->addMonths($months); - break; - case 'yearly': - $date->addYears($add); - break; - } - return $date; - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Helper/Toolkit/ToolkitInterface.php b/app/lib/Firefly/Helper/Toolkit/ToolkitInterface.php deleted file mode 100644 index aa02c9bca9..0000000000 --- a/app/lib/Firefly/Helper/Toolkit/ToolkitInterface.php +++ /dev/null @@ -1,52 +0,0 @@ -_accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); - $this->_repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - $this->_piggybanks = \App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface'); - - - } - - /** - * The final step in the import routine is to get all transactions which have one of their accounts - * still set to "import", which means it is a cash transaction. This routine will set them all to cash instead. - * - * If there was no account present for these accounts in the import routine (no beneficiary set), Firefly - * II would fall back to the import account. - * - * @param Job $job - * @param array $payload - */ - public function cleanImportAccount(Job $job, array $payload) - { - - /** @var \Importmap $importMap */ - $importMap = $this->_repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - // two import account types. - $importAccountType = $this->_accounts->findAccountType('Import account'); - $cashAccountType = $this->_accounts->findAccountType('Cash account'); - - // find or create import account: - $importAccount = $this->_accounts->firstOrCreate( - [ - 'name' => 'Import account', - 'account_type_id' => $importAccountType->id, - 'active' => 1, - 'user_id' => $user->id, - ] - ); - - // find or create cash account: - $cashAccount = $this->_accounts->firstOrCreate( - [ - 'name' => 'Cash account', - 'account_type_id' => $cashAccountType->id, - 'active' => 1, - 'user_id' => $user->id, - ] - ); - - // update all users transactions: - $count = \DB::table('transactions') - ->where('account_id', $importAccount->id)->count(); - - \DB::table('transactions') - ->where('account_id', $importAccount->id) - ->update(['account_id' => $cashAccount->id]); - - \Log::debug('Updated ' . $count . ' transactions from Import Account to cash.'); - $job->delete(); // no count fix - } - - /** - * @param \User $user - */ - protected function overruleUser(\User $user) - { - $this->_accounts->overruleUser($user); - $this->_repository->overruleUser($user); - $this->_piggybanks->overruleUser($user); - } - - /** - * This job queues new jobs that will connect components to their proper transactions and updates the - * expense account: categories, budgets an beneficiaries used to be components. - * - * @param Job $job - * @param array $payload - */ - public function importComponentTransaction(Job $job, array $payload) - { - /** @var \Importmap $importMap */ - $importMap = $this->_repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - /* - * Took too long to fix this: - */ - if ($job->attempts() > 10) { - \Log::error('Could not map transaction to component after 10 tries. KILL'); - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - return; - } - - - /* - * Prep some vars from the payload - */ - $transactionId = intval($payload['data']['transaction_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * We don't know what kind of component we have. So we search for it. We have a specific function - * for this: - */ - $oldComponentMap = $this->_repository->findImportComponentMap($importMap, $componentId); - - /* - * If the map is null, the component (whatever it is) is not imported yet, and we release the job. - */ - if (is_null($oldComponentMap)) { - \Log::notice('No map for this component, release transaction/component import.'); - - /* - * When in sync, its pointless to release jobs. Simply remove them. - */ - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - - return; - } - - /* - * Switch on the class found in the map, and push a new job to update the transaction journal: - */ - switch ($oldComponentMap->class) { - default: - \Log::error('Cannot handle "' . $oldComponentMap->class . '" in component<>transaction routine!'); - $job->delete(); - break; - case 'Budget': - \Log::debug('Push job to connect budget to transaction #' . $transactionId); - \Queue::push( // count fixed - 'Firefly\Storage\Budget\BudgetRepositoryInterface@importUpdateTransaction', $payload - ); - $importMap->totaljobs++; - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - break; - case 'Category': - \Log::debug('Push job to connect category to transaction #' . $transactionId); - \Queue::push( // count fixed - 'Firefly\Storage\Category\CategoryRepositoryInterface@importUpdateTransaction', $payload - ); - - $importMap->totaljobs++; - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - break; - case 'Account': - \Log::debug('Push job to connect account to transaction #' . $transactionId); - \Queue::push( // count fixed - 'Firefly\Storage\Account\AccountRepositoryInterface@importUpdateTransaction', $payload - ); - - $importMap->totaljobs++; - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - break; - } - return; - - - } - - /** - * This job queues new jobs that will connect components to their proper transfers and updates the - * expense account: categories, budgets an beneficiaries used to be components. Even though not all - * of the transfers used to have these components, we check for them all. - * - * @param Job $job - * @param array $payload - */ - public function importComponentTransfer(Job $job, array $payload) - { - /** @var \Importmap $importMap */ - $importMap = $this->_repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - /* - * Took too long to fix this: - */ - if ($job->attempts() > 10) { - \Log::error('Could not map transaction to component after 10 tries. KILL'); - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - return; - } - - /* - * Prep some vars from the payload - */ - $transferId = intval($payload['data']['transfer_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * We don't know what kind of component we have. So we search for it. We have a specific function - * for this: - */ - $oldComponentMap = $this->_repository->findImportComponentMap($importMap, $componentId); - - /* - * If the map is null, the component (whatever it is) is not imported yet, and we release the job. - */ - if (is_null($oldComponentMap)) { - \Log::notice('No map for this component, release transfer/component import.'); - /* - * When in sync, its pointless to release jobs. Simply remove them. - */ - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Switch on the class found in the map, and push a new job to update the transaction journal: - */ - switch ($oldComponentMap->class) { - default: - \Log::error('Cannot handle "' . $oldComponentMap->class . '" in component<>transfer routine!'); - $job->delete(); - break; - case 'Category': - \Log::debug('Push job to connect category to transfer #' . $transferId); - \Queue::push( // count fixed - 'Firefly\Storage\Category\CategoryRepositoryInterface@importUpdateTransfer', $payload - ); - - $importMap->totaljobs++; - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - break; - case 'Budget': - \Log::debug('Push job to connect budget to transfer #' . $transferId); - \Queue::push( // count fixed - 'Firefly\Storage\Budget\BudgetRepositoryInterface@importUpdateTransfer', $payload - ); - $importMap->totaljobs++; - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - break; - } - - - } - - /** - * This job will see if the particular setting is a 'piggyAccount' setting, - * one we need to fix all imported piggy banks. - * - * @param Job $job - * @param array $payload - */ - public function importSetting(Job $job, array $payload) - { - /** @var \Importmap $importMap */ - $importMap = $this->_repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error('No account found for piggyAccount setting after 10 tries. KILL!'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - $name = $payload['data']['name']; - switch ($name) { - default: - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed. - return; - break; - case 'piggyAccount': - - /* - * If user has this account, update all piggy banks: - */ - $accountID = intval($payload['data']['value']); - - /* - * Is account imported already? - */ - $importEntry = $this->_repository->findImportEntry($importMap, 'Account', $accountID); - - /* - * We imported this account already. - */ - if ($importEntry) { - $all = $this->_piggybanks->get(); - $account = $this->_accounts->find($importEntry->new); - /* - * Update all piggy banks. - */ - if (!is_null($account)) { - \Log::debug('Updating all piggybanks, found the right setting.'); - foreach ($all as $piggy) { - $piggy->account()->associate($account); - unset($piggy->leftInAccount); - $piggy->save(); - } - } - } else { - \Log::notice('Account not yet imported, hold or 5 minutes.'); - /* - * When in sync, its pointless to release jobs. Simply remove them. - */ - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - } - break; - } - - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed. - - } - - /** - * This job will loop and queue jobs for the import file; almost every set of records will be imported. - * - * @param Job $job - * @param $payload - * - * @SuppressWarnings(PHPMD.CamelCasePropertyName) - */ - 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) && !is_null($user)) { - /* - * Make an import map. Need it to refer back to import. - */ - $importMap = new \Importmap; - $importMap->user()->associate($user); - $importMap->file = $filename; - $importMap->totaljobs = 0; - $importMap->jobsdone = 0; - $importMap->save(); - - $totalJobs = 0; - - /* - * Loop over all data in the JSON file, then create jobs. - */ - $raw = file_get_contents($filename); - $JSON = json_decode($raw); - - // first import all asset accounts: - foreach ($JSON->accounts as $entry) { - \Log::debug('Create job to import asset account'); - \Queue::push( // count fixed - 'Firefly\Storage\Account\AccountRepositoryInterface@importAccount', [ - 'data' => $entry, - 'class' => 'Account', - 'account_type' => 'Asset account', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - // then import all beneficiaries: - foreach ($JSON->components as $entry) { - if ($entry->type->type == 'beneficiary') { - \Log::debug('Create job to import expense account'); - \Queue::push( // count fixed - 'Firefly\Storage\Account\AccountRepositoryInterface@importAccount', [ - 'data' => $entry, - 'class' => 'Account', - 'account_type' => 'Expense account', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - } - - // then import all categories. - foreach ($JSON->components as $entry) { - if ($entry->type->type == 'category') { - \Log::debug('Create job to import category'); - \Queue::push( // count fixed - 'Firefly\Storage\Category\CategoryRepositoryInterface@importCategory', [ - 'data' => $entry, - 'class' => 'Category', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - } - - // then import all budgets: - foreach ($JSON->components as $entry) { - if ($entry->type->type == 'budget') { - \Log::debug('Create job to import budget'); - \Queue::push( // count fixed - 'Firefly\Storage\Budget\BudgetRepositoryInterface@importBudget', [ - 'data' => $entry, - 'class' => 'Budget', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - } - - // then import all limits. - foreach ($JSON->limits as $entry) { - \Log::debug('Create job to import limit'); - \Queue::push( // count fixed - 'Firefly\Storage\Limit\LimitRepositoryInterface@importLimit', [ - 'data' => $entry, - 'class' => 'Limit', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - // all piggy banks - foreach ($JSON->piggybanks as $entry) { - \Log::debug('Create job to import piggy bank'); - \Queue::push( // count fixed - 'Firefly\Storage\Piggybank\PiggybankRepositoryInterface@importPiggybank', [ - 'data' => $entry, - 'class' => 'Piggybank', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - // all predictables. - foreach ($JSON->predictables as $entry) { - \Log::debug('Create job to import predictable'); - \Queue::push( // count fixed - 'Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface@importPredictable', [ - 'data' => $entry, - 'class' => 'Predictable', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - // all settings (to fix the piggy banks) - foreach ($JSON->settings as $entry) { - \Log::debug('Create job to import setting'); - \Queue::push( // count fixed - 'Firefly\Queue\Import@importSetting', [ - 'data' => $entry, - 'class' => 'Setting', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - // all transactions - foreach ($JSON->transactions as $entry) { - - \Log::debug('Create job to import transaction'); - \Queue::push( // count fixed - 'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface@importTransaction', [ - 'data' => $entry, - 'class' => 'Transaction', - 'mapID' => $importMap->id - ] - ); - - $totalJobs++; - } - - // all transfers - foreach ($JSON->transfers as $entry) { - \Log::debug('Create job to import transfer'); - \Queue::push( // count fixed - 'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface@importTransfer', [ - 'data' => $entry, - 'class' => 'Transfer', - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - // then, fix all component <> transaction links - foreach ($JSON->component_transaction as $entry) { - \Log::debug('Create job to import components_transaction'); - \Queue::push( // count fixed - 'Firefly\Queue\Import@importComponentTransaction', - [ - 'data' => $entry, - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - - // then, fix all component <> transfer links - foreach ($JSON->component_transfer as $entry) { - \Log::debug('Create job to import components_transfer'); - \Queue::push( // count fixed - 'Firefly\Queue\Import@importComponentTransfer', - [ - 'data' => $entry, - 'mapID' => $importMap->id - ] - ); - $totalJobs++; - } - - $importMap->totaljobs = $totalJobs; - $importMap->save(); - /* - * We save the import map which now holds the number of jobs we've got planned. - */ - - \Queue::push('Firefly\Queue\Import@cleanImportAccount', ['mapID' => $importMap->id]); - - $job->delete(); // count fixed - - \Log::debug('Done with job "start"'); - } - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Account/AccountRepositoryInterface.php b/app/lib/Firefly/Storage/Account/AccountRepositoryInterface.php deleted file mode 100644 index 147aacaaff..0000000000 --- a/app/lib/Firefly/Storage/Account/AccountRepositoryInterface.php +++ /dev/null @@ -1,146 +0,0 @@ -_user = \Auth::user(); - } - - /** - * @return mixed - */ - public function count() - { - return $this->_user->accounts()->count(); - - } - - /** - * @param \Account $account - * - * @return bool|mixed - */ - public function destroy(\Account $account) - { - // find all transaction journals related to this account: - $journals = \TransactionJournal::withRelevantData()->accountIs($account)->get(['transaction_journals.*']); - $accountIDs = []; - - /** @var \TransactionJournal $journal */ - foreach ($journals as $journal) { - // remember the account id's of the transactions involved: - foreach ($journal->transactions as $t) { - $accountIDs[] = $t->account_id; - } - $journal->delete(); - - } - $accountIDs = array_unique($accountIDs); - if (count($accountIDs) > 0) { - // find the "initial balance" type accounts in this list. Should be just 1. - $query = $this->_user->accounts()->accountTypeIn(['Initial balance account']) - ->whereIn('accounts.id', $accountIDs); - if ($query->count() == 1) { - $iba = $query->first(['accounts.*']); - $iba->delete(); - } - } - $account->delete(); - - /** - * - * - * Also delete: initial balance, initial balance account, and transactions - */ - - return true; - } - - /** - * @param $id - * - * @return |Account|null - */ - public function findAssetAccountById($id) - { - return $this->_user->accounts()->find($id); - } - - /** - * This method finds the expense account mentioned by name. This method is a sneaky little hobbits, - * because when you feed it "Import account" it will always return an import account of that type. - * - * @param $name - * @param $create - * - * @return null|\Account - */ - public function findExpenseAccountByName($name, $create = true) - { - $cashType = $this->findAccountType('Cash account'); - $importType = $this->findAccountType('Import account'); - // catch Import account: - if ($name == 'Import account') { - - $import = $this->firstOrCreate( - [ - 'name' => 'Import account', - 'user_id' => $this->_user->id, - 'account_type_id' => $importType->id, - 'active' => 1 - ] - ); - return $import; - } - - // find account: - - $account = $this->_user->accounts()->where('name', $name)->accountTypeIn( - ['Expense account', 'Beneficiary account'] - )->first(['accounts.*']); - - // create if not found: - if (strlen($name) > 0 && is_null($account) && $create === true) { - $type = $this->findAccountType('Expense account'); - $set = [ - 'name' => $name, - 'user_id' => $this->_user->id, - 'active' => 1, - 'account_type_id' => $type->id - ]; - $account = $this->firstOrCreate($set); - } else if (strlen($name) > 0 && is_null($account) && $create === false) { - return null; - } - - - // find cash account as fall back: - if (is_null($account)) { - - $account = $this->_user->accounts()->where('account_type_id', $cashType->id)->first(); - } - - // create cash account as ultimate fall back: - if (is_null($account)) { - $set = [ - 'name' => 'Cash account', - 'user_id' => $this->_user->id, - 'active' => 1, - 'account_type_id' => $cashType->id - ]; - $account = $this->firstOrCreate($set); - } - - if ($account->active == 0 && $account->account_type_id != $cashType->id) { - return null; - } - - return $account; - } - - /** - * @param $type - * - * @return \AccountType|null - */ - public function findAccountType($type) - { - return \AccountType::where('type', $type)->first(); - } - - public function firstOrCreate(array $data) - { - return \Account::firstOrCreate($data); - } - - /** - * @param $name - * @param $create - * - * @return |Account|null - */ - public function findRevenueAccountByName($name, $create = true) - { - // catch Import account: - if ($name == 'Import account') { - $importType = $this->findAccountType('Import account'); - $import = $this->firstOrCreate( - [ - 'name' => 'Import account', - 'user_id' => $this->_user->id, - 'account_type_id' => $importType->id, - 'active' => 1 - ] - ); - return $import; - } - - // find account: - $type = $this->findAccountType('Revenue account'); - $account = $this->_user->accounts()->where('name', $name)->where('account_type_id', $type->id)->first(); - - // create if not found: - if (strlen($name) > 0 && is_null($account) && $create === true) { - $set = [ - 'name' => $name, - 'user_id' => $this->_user->id, - 'active' => 1, - 'account_type_id' => $type->id - ]; - $account = $this->firstOrCreate($set); - } else if (strlen($name) > 0 && is_null($account) && $create === false) { - return null; - } - - // find cash account as fall back: - if (is_null($account)) { - $cashType = $this->findAccountType('Cash account'); - $account = $this->_user->accounts()->where('account_type_id', $cashType->id)->first(); - } - - // create cash account as ultimate fall back: - if (is_null($account)) { - $set = [ - 'name' => 'Cash account', - 'user_id' => $this->_user->id, - 'active' => 1, - 'account_type_id' => $cashType->id - ]; - $account = $this->firstOrCreate($set); - } - - if ($account->active == 0) { - return null; - } - - return $account; - } - - public function getByAccountType(\AccountType $type) - { - return $this->_user->accounts()->with('accounttype')->orderBy('name', 'ASC') - ->where('account_type_id', $type->id)->get(); - } - - /** - * @param $ids - * - * @return array|mixed - */ - public function getByIds(array $ids) - { - if (count($ids) > 0) { - return $this->_user->accounts()->with('accounttype')->whereIn('id', $ids)->orderBy('name', 'ASC')->get(); - } else { - return $this->getActiveDefault(); - } - } -// -// /** -// * @param $name -// * -// * @return \Account|mixed|null -// */ -// public function createOrFindBeneficiary($name) -// { -// if (is_null($name) || strlen($name) == 0) { -// return null; -// } -// $type = \AccountType::where('type', 'Expense account')->first(); -// return $this->createOrFind($name, $type); -// } -// -// /** -// * @param $name -// * @param \AccountType $type -// * -// * @return \Account|mixed -// */ -// public function createOrFind($name, \AccountType $type = null) -// { -// $account = $this->findByName($name, $type); -// if (!$account) { -// $data = [ -// 'name' => $name, -// 'account_type' => $type -// ]; -// -// return $this->store($data); -// } -// -// return $account; -// } -// -// /** -// * @param $name -// * @param \AccountType $type -// * -// * @return mixed -// */ -// public function findByName($name, \AccountType $type = null) -// { -// $type = is_null($type) ? \AccountType::where('type', 'Asset account')->first() : $type; -// -// return $this->_user->accounts()->where('account_type_id', $type->id) -// ->where('name', 'like', '%' . $name . '%') -// ->first(); -// } - - /** - * @return mixed - */ - public function getActiveDefault() - { - return $this->_user->accounts()->accountTypeIn(['Default account', 'Asset account'])->where( - 'accounts.active', 1 - ) - ->get(['accounts.*']); - } - - /** - * @return mixed - */ - public function getDefault() - { - return $this->_user->accounts()->accountTypeIn(['Default account', 'Asset account']) - ->orderBy('accounts.name', 'ASC')->get(['accounts.*']); - } - - /** - * Gets a list of accounts that have the mentioned type. Will automatically convert - * strings in this array to actual (model) account types. - * - * @param array $types - * - * @return Collection - */ - public function getOfTypes(array $types) - { - $accounts = $this->_user->accounts()->accountTypeIn($types)->get(['accounts.*']); - return $accounts; - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importAccount(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - /* - * maybe Account is already imported: - */ - $importEntry = $repository->findImportEntry($importMap, 'Account', intval($payload['data']['id'])); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported ' . $payload['data']['name'] . ' of type ' . $payload['account_type']); - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - return; - } - - /* - * find the payload's account type: - */ - $payload['account_type'] = isset($payload['account_type']) ? $payload['account_type'] : 'Expense account'; - $type = $this->findAccountType($payload['account_type']); - - /* - * Create data array for store() procedure. - */ - $data = [ - 'account_type' => $type, - 'name' => $payload['data']['name'], - ]; - if (isset($payload['data']['openingbalance'])) { - $data['openingbalance'] = floatval($payload['data']['openingbalance']); - $data['openingbalancedate'] = $payload['data']['openingbalancedate']; - } - if (isset($payload['data']['inactive'])) { - $data['active'] = intval($payload['data']['inactive']) == 0 ? 1 : 0; - } - - /* - * Try to store: - */ - $account = $this->store($data); - - /* - * Check for failure. - */ - if (count($account->errors()) > 0) { - \Log::error('Account creation error: ' . $account->errors()->first()); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - \Log::debug('Imported ' . $payload['account_type'] . ': ' . $payload['data']['name']); - - /* - * Save meta data - */ - $repository->store($importMap, 'Account', intval($payload['data']['id']), $account->id); - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed. - return; - } - -// /** -// * Used for import -// * -// * @param $name -// * -// * @return mixed -// */ -// public function findByNameAny($name) -// { -// return $this->_user->accounts() -// ->where('name', 'like', '%' . $name . '%') -// ->first(); -// } - - /** - * @param $data - * - * @return \Account - * @throws \Firefly\Exception\FireflyException - */ - public function store($data) - { - /** - * If the AccountType has been passed through, use it: - */ - if (isset($data['account_type']) && is_object($data['account_type']) - && get_class($data['account_type']) == 'AccountType' - ) { - $accountType = $data['account_type']; - } else if (isset($data['account_type']) && is_string($data['account_type'])) { - // if it isnt but set as string, find it: - $accountType = \AccountType::where('type', $data['account_type'])->first(); - - } else { - $accountType = \AccountType::where('type', 'Asset account')->first(); - } - $active = isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval( - $data['active'] - ) : 1; - - /** - * Create new account: - */ - $account = new \Account; - $account->accountType()->associate($accountType); - $account->user()->associate($this->_user); - - $account->name = $data['name']; - $account->active - = isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval( - $data['active'] - ) : 1; - - // try to save it: - try { - if ($account->save()) { - // create initial balance, if necessary: - if (isset($data['openingbalance']) && isset($data['openingbalancedate'])) { - $amount = floatval($data['openingbalance']); - $date = new Carbon($data['openingbalancedate']); - if ($amount != 0) { - $this->_createInitialBalance($account, $amount, $date); - } - } - } - } catch (QueryException $e) { - // do nothing - } - - - // whatever the result, return the account. - return $account; - } - - /** - * @param \Account $account - * @param int $amount - * @param Carbon $date - * - * @return bool - * @SuppressWarnings(PHPMD.CamelCaseMethodName) - */ - protected function _createInitialBalance(\Account $account, $amount = 0, Carbon $date) - { - /* - * The repositories we need: - */ - /** @var \Firefly\Helper\Controllers\TransactionInterface $transactions */ - $transactions = \App::make('Firefly\Helper\Controllers\TransactionInterface'); - $transactions->overruleUser($this->_user); - - - /* - * get account type: - */ - $initialBalanceAT = $this->findAccountType('Initial balance account'); - - /* - * create new account - */ - $initial = new \Account; - $initial->accountType()->associate($initialBalanceAT); - $initial->user()->associate($this->_user); - $initial->name = $account->name . ' initial balance'; - $initial->active = 0; - if ($initial->validate()) { - $initial->save(); - /* - * create new transaction journal (and transactions): - */ - - $set = [ - 'account_from_id' => $initial->id, - 'account_to_id' => $account->id, - 'description' => 'Initial Balance for ' . $account->name, - 'what' => 'Opening balance', - 'amount' => $amount, - 'category' => '', - 'date' => $date->format('Y-m-d') - ]; - $transactions->store($set); - - return true; - } - - return false; - } - - /** - * Takes a transaction/account component and updates the transaction journal to match. - * - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importUpdateTransaction(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error('Never found budget/account combination "' . $payload['data']['transaction_id'] . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed. - return; - } - - /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ - $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); - $journals->overruleUser($user); - - /* - * Prep some vars from the payload - */ - $transactionId = intval($payload['data']['transaction_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * Find the import map for both: - */ - $accountMap = $repository->findImportEntry($importMap, 'Account', $componentId); - $transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId); - - /* - * Either may be null: - */ - if (is_null($accountMap) || is_null($transactionMap)) { - \Log::notice('No map found in account/transaction mapper. Release.'); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Find the account and the transaction: - */ - $account = $this->find($accountMap->new); - /** @var \TransactionJournal $journal */ - $journal = $journals->find($transactionMap->new); - - /* - * If either is null, release: - */ - if (is_null($account) || is_null($journal)) { - \Log::notice('Map is incorrect in account/transaction mapper. Release.'); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Update one of the journal's transactions to have the right account: - */ - $importType = $this->findAccountType('Import account'); - /** @var \Transaction $transaction */ - $updated = false; - \Log::debug( - 'Connect "' . $account->name . '" (#' . $account->id . ') to "' . $journal->description . '" (#' - . $journal->id . ')' - ); - foreach ($journal->transactions as $index => $transaction) { - /* - * If it's of the right type, update it! - */ - \Log::debug( - 'Transaction ' . $index . ' (#' . $transaction->id . '): [' . $transaction->account->account_type_id - . ' vs. ' . $importType->id . ']' - ); - if ($transaction->account->account_type_id == $importType->id) { - $transaction->account()->associate($account); - $transaction->save(); - $updated = true; - \Log::debug( - 'Connected expense account "' . $account->name . '" to journal "' . $journal->description . '"' - ); - } - } - if ($updated === false) { - \Log::error( - 'Did not connect transactions of journal #' . $journal->id . ' to expense account ' . $account->id - ); - - } - - $journal->save(); - - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - /** - * @param $accountId - * - * @return mixed - */ - public function find($accountId) - { - return $this->_user->accounts()->where('id', $accountId)->first(); - } - - /** - * @param \Account $account - * @param $data - * - * @return \Account|mixed - */ - public function update(\Account $account, $data) - { - // update account accordingly: - $account->name = $data['name']; - if ($account->validate()) { - $account->save(); - } - // update initial balance if necessary: - if (isset($data['openingbalance']) && floatval($data['openingbalance']) != 0) { - - /** @var \Firefly\Helper\Controllers\AccountInterface $interface */ - $interface = \App::make('Firefly\Helper\Controllers\AccountInterface'); - - if ($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account') { - - - $journal = $interface->openingBalanceTransaction($account); - if ($journal) { - $journal->date = new Carbon($data['openingbalancedate']); - $journal->transactions[0]->amount = floatval($data['openingbalance']) * -1; - $journal->transactions[1]->amount = floatval($data['openingbalance']); - $journal->transactions[0]->save(); - $journal->transactions[1]->save(); - $journal->save(); - } - } - } - - return $account; - } - - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Budget/BudgetRepositoryInterface.php b/app/lib/Firefly/Storage/Budget/BudgetRepositoryInterface.php deleted file mode 100644 index 87de3a6ed9..0000000000 --- a/app/lib/Firefly/Storage/Budget/BudgetRepositoryInterface.php +++ /dev/null @@ -1,88 +0,0 @@ -_user = \Auth::user(); - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importBudget(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - /* - * maybe Budget is already imported: - */ - $importEntry = $repository->findImportEntry($importMap, 'Budget', intval($payload['data']['id'])); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported budget ' . $payload['data']['name']); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /* - * maybe Budget is already imported. - */ - $budget = $this->findByName($payload['data']['name']); - - if (is_null($budget)) { - /* - * Not imported yet. - */ - $budget = $this->store($payload['data']); - $repository->store($importMap, 'Budget', $payload['data']['id'], $budget->id); - \Log::debug('Imported budget "' . $payload['data']['name'] . '".'); - } else { - /* - * already imported. - */ - $repository->store($importMap, 'Budget', $payload['data']['id'], $budget->id); - \Log::debug('Already had budget "' . $payload['data']['name'] . '".'); - } - - // update map: - $importMap->jobsdone++; - $importMap->save(); - - // delete job. - $job->delete(); // count fixed - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - /** - * @param $budgetName - * - * @return \Budget|null - */ - public function findByName($budgetName) - { - - return $this->_user->budgets()->whereName($budgetName)->first(); - } - - /** - * @param $data - * - * @return \Budget - */ - public function store($data) - { - $budget = new \Budget; - $budget->name = $data['name']; - $budget->user()->associate($this->_user); - $budget->save(); - - // if limit, create limit (repetition itself will be picked up elsewhere). - if (isset($data['amount']) && floatval($data['amount']) > 0) { - $startDate = new Carbon; - $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(); - } - - return $budget; - } - - /** - * Takes a transfer/budget component and updates the transaction journal to match. - * - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importUpdateTransfer(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error('Never found budget/transfer combination "' . $payload['data']['transfer_id'] . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - - /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ - $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); - $journals->overruleUser($user); - - /* - * Prep some vars from the payload - */ - $transferId = intval($payload['data']['transfer_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * Find the import map for both: - */ - $budgetMap = $repository->findImportEntry($importMap, 'Budget', $componentId); - $transferMap = $repository->findImportEntry($importMap, 'Transfer', $transferId); - - /* - * Either may be null: - */ - if (is_null($budgetMap) || is_null($transferMap)) { - \Log::notice('No map found in budget/transfer mapper. Release.'); - if(\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Find the budget and the transaction: - */ - $budget = $this->find($budgetMap->new); - /** @var \TransactionJournal $journal */ - $journal = $journals->find($transferMap->new); - - /* - * If either is null, release: - */ - if (is_null($budget) || is_null($journal)) { - \Log::notice('Map is incorrect in budget/transfer mapper. Release.'); - if(\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Update journal to have budget: - */ - $journal->budgets()->save($budget); - $journal->save(); - \Log::debug('Connected budget "' . $budget->name . '" to journal "' . $journal->description . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - - return; - } - - /** - * Takes a transaction/budget component and updates the transaction journal to match. - * - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importUpdateTransaction(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error('Never found budget/transaction combination "' . $payload['data']['transaction_id'] . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - - /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ - $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); - $journals->overruleUser($user); - - /* - * Prep some vars from the payload - */ - $transactionId = intval($payload['data']['transaction_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * Find the import map for both: - */ - $budgetMap = $repository->findImportEntry($importMap, 'Budget', $componentId); - $transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId); - - /* - * Either may be null: - */ - if (is_null($budgetMap) || is_null($transactionMap)) { - \Log::notice('No map found in budget/transaction mapper. Release.'); - if(\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Find the budget and the transaction: - */ - $budget = $this->find($budgetMap->new); - /** @var \TransactionJournal $journal */ - $journal = $journals->find($transactionMap->new); - - /* - * If either is null, release: - */ - if (is_null($budget) || is_null($journal)) { - \Log::notice('Map is incorrect in budget/transaction mapper. Release.'); - if(\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Update journal to have budget: - */ - $journal->budgets()->save($budget); - $journal->save(); - \Log::debug('Connected budget "' . $budget->name . '" to journal "' . $journal->description . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - - return; - } - - /** - * @param $budgetId - * - * @return \Budget|null - */ - public function find($budgetId) - { - - return $this->_user->budgets()->find($budgetId); - } - - /** - * @param \Budget $budget - * - * @return bool - */ - public function destroy(\Budget $budget) - { - $budget->delete(); - - return true; - } - - /** - * @return Collection - */ - public function get() - { - $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(); - return $set; - } - - /** - * @param \Budget $budget - * @param $data - * - * @return \Budget|mixed - */ - public function update(\Budget $budget, $data) - { - // update account accordingly: - $budget->name = $data['name']; - if ($budget->validate()) { - $budget->save(); - } - - return $budget; - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Category/CategoryRepositoryInterface.php b/app/lib/Firefly/Storage/Category/CategoryRepositoryInterface.php deleted file mode 100644 index 15c6785548..0000000000 --- a/app/lib/Firefly/Storage/Category/CategoryRepositoryInterface.php +++ /dev/null @@ -1,95 +0,0 @@ -_user = \Auth::user(); - } - - /** - * Takes a transfer/category component and updates the transaction journal to match. - * - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importUpdateTransfer(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - - if ($job->attempts() > 10) { - \Log::error('Never found category/transfer combination "' . $payload['data']['transfer_id'] . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed. - return; - } - - - /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ - $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); - $journals->overruleUser($user); - - /* - * Prep some vars from the payload - */ - $transferId = intval($payload['data']['transfer_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * Find the import map for both: - */ - $categoryMap = $repository->findImportEntry($importMap, 'Category', $componentId); - $transferMap = $repository->findImportEntry($importMap, 'Transfer', $transferId); - - /* - * Either may be null: - */ - if (is_null($categoryMap) || is_null($transferMap)) { - \Log::notice('No map found in category/transfer mapper. Release.'); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Find the budget and the transaction: - */ - $category = $this->find($categoryMap->new); - /** @var \TransactionJournal $journal */ - $journal = $journals->find($transferMap->new); - - /* - * If either is null, release: - */ - if (is_null($category) || is_null($journal)) { - \Log::notice('Map is incorrect in category/transfer mapper. Release.'); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Update journal to have budget: - */ - $journal->categories()->save($category); - $journal->save(); - \Log::debug('Connected category "' . $category->name . '" to journal "' . $journal->description . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - - return; - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - /** - * @param $categoryId - * - * @return mixed - */ - public function find($categoryId) - { - return $this->_user->categories()->find($categoryId); - } - - /** - * Takes a transaction/category component and updates the transaction journal to match. - * - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importUpdateTransaction(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - - if ($job->attempts() > 10) { - \Log::error('Never found category/transaction combination "' . $payload['data']['transaction_id'] . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed. - return; - } - - - /** @var \Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface $journals */ - $journals = \App::make('Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface'); - $journals->overruleUser($user); - - /* - * Prep some vars from the payload - */ - $transactionId = intval($payload['data']['transaction_id']); - $componentId = intval($payload['data']['component_id']); - - /* - * Find the import map for both: - */ - $categoryMap = $repository->findImportEntry($importMap, 'Category', $componentId); - $transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId); - - /* - * Either may be null: - */ - if (is_null($categoryMap) || is_null($transactionMap)) { - \Log::notice('No map found in category/transaction mapper. Release.'); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Find the budget and the transaction: - */ - $category = $this->find($categoryMap->new); - /** @var \TransactionJournal $journal */ - $journal = $journals->find($transactionMap->new); - - /* - * If either is null, release: - */ - if (is_null($category) || is_null($journal)) { - \Log::notice('Map is incorrect in category/transaction mapper. Release.'); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Update journal to have budget: - */ - $journal->categories()->save($category); - $journal->save(); - \Log::debug('Connected category "' . $category->name . '" to journal "' . $journal->description . '"'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - - return; - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importCategory(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - /* - * Maybe the category has already been imported - */ - $importEntry = $repository->findImportEntry($importMap, 'Category', intval($payload['data']['id'])); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported category ' . $payload['data']['name']); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /* - * try to find category first - */ - $current = $this->findByName($payload['data']['name']); - - /* - * If not found, create it: - */ - if (is_null($current)) { - $category = $this->store($payload['data']); - $repository->store($importMap, 'Category', $payload['data']['id'], $category->id); - \Log::debug('Imported category "' . $payload['data']['name'] . '".'); - } else { - $repository->store($importMap, 'Category', $payload['data']['id'], $current->id); - \Log::debug('Already had category "' . $payload['data']['name'] . '".'); - } - - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /** - * @param $name - * - * @return mixed - */ - public function findByName($name) - { - if ($name == '' || strlen($name) == 0) { - return null; - } - - return $this->_user->categories()->where('name', $name)->first(); - - } - - /** - * @param $data - * - * @return \Category|mixed - */ - public function store($data) - { - $category = new \Category; - $category->name = $data['name']; - - $category->user()->associate($this->_user); - $category->save(); - - return $category; - } - - /** - * @param $name - * - * @return \Category|mixed - */ - public function firstOrCreate($name) - { - if (strlen($name) == 0) { - return null; - } - $data = [ - 'name' => $name, - 'user_id' => $this->_user->id, - ]; - return \Category::firstOrCreate($data); - - } - - /** - * @param $category - * - * @return bool|mixed - */ - public function destroy($category) - { - $category->delete(); - - return true; - } - - /** - * @return mixed - */ - public function get() - { - return $this->_user->categories()->orderBy('name', 'ASC')->get(); - } - - /** - * @param $category - * @param $data - * - * @return mixed - */ - public function update($category, $data) - { - // update account accordingly: - $category->name = $data['name']; - if ($category->validate()) { - $category->save(); - } - - return $category; - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Import/EloquentImportRepository.php b/app/lib/Firefly/Storage/Import/EloquentImportRepository.php deleted file mode 100644 index 2cc1139fa1..0000000000 --- a/app/lib/Firefly/Storage/Import/EloquentImportRepository.php +++ /dev/null @@ -1,58 +0,0 @@ -_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(); - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Import/ImportRepositoryInterface.php b/app/lib/Firefly/Storage/Import/ImportRepositoryInterface.php deleted file mode 100644 index e5a12eeb48..0000000000 --- a/app/lib/Firefly/Storage/Import/ImportRepositoryInterface.php +++ /dev/null @@ -1,51 +0,0 @@ -_user = \Auth::user(); - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importLimit(Job $job, array $payload) - { - - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error( - 'No budget found for limit #' . $payload['data']['id'] . '. Prob. for another component. KILL!' - ); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed. - return; - } - - /** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgets */ - $budgets = \App::make('Firefly\Storage\Budget\BudgetRepositoryInterface'); - $budgets->overruleUser($user); - - /* - * Find the budget this limit is part of: - */ - $importEntry = $repository->findImportEntry($importMap, 'Budget', intval($payload['data']['component_id'])); - - /* - * There is no budget (yet?) - */ - if (is_null($importEntry)) { - $componentId = intval($payload['data']['component_id']); - \Log::warning('Budget #' . $componentId . ' not found. Requeue import job.'); - if(\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * Find budget import limit is for: - */ - $budget = $budgets->find($importEntry->new); - if (!is_null($budget)) { - /* - * Is actual limit already imported? - */ - $limit = $this->findByBudgetAndDate($budget, new Carbon($payload['data']['date'])); - if (is_null($limit)) { - /* - * It isn't imported yet. - */ - $payload['data']['budget_id'] = $budget->id; - $payload['data']['startdate'] = $payload['data']['date']; - $payload['data']['period'] = 'monthly'; - /* - * Store limit, and fire event for LimitRepetition. - */ - $limit = $this->store($payload['data']); - $repository->store($importMap, 'Limit', $payload['data']['id'], $limit->id); - \Event::fire('limits.store', [$limit]); - \Log::debug('Imported limit for budget ' . $budget->name); - } else { - /* - * Limit already imported: - */ - $repository->store($importMap, 'Budget', $payload['data']['id'], $limit->id); - } - } else { - \Log::error(print_r($importEntry,true)); - \Log::error('Cannot import limit! Big bad error!'); - } - - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - public function findByBudgetAndDate(\Budget $budget, Carbon $date) - { - return \Limit::whereComponentId($budget->id)->where('startdate', $date->format('Y-m-d'))->first(); - } - - /** - * @param $data - * - * @return \Limit - */ - public function store($data) - { - $budget = \Budget::find($data['budget_id']); - if (is_null($budget)) { - \Session::flash('error', 'No such budget.'); - - return new \Limit; - } - // set the date to the correct start period: - $date = new Carbon($data['startdate']); - switch ($data['period']) { - case 'daily': - $date->startOfDay(); - break; - case 'weekly': - $date->startOfWeek(); - break; - case 'monthly': - $date->startOfMonth(); - break; - case 'quarterly': - $date->firstOfQuarter(); - break; - case 'half-year': - - if (intval($date->format('m')) >= 7) { - $date->startOfYear(); - $date->addMonths(6); - } else { - $date->startOfYear(); - } - break; - case 'yearly': - $date->startOfYear(); - break; - } - // find existing: - $count = \Limit:: - leftJoin('components', 'components.id', '=', 'limits.component_id')->where( - 'components.user_id', $this->_user->id - )->where('startdate', $date->format('Y-m-d'))->where('component_id', $data['budget_id'])->where( - 'repeat_freq', $data['period'] - )->count(); - if ($count > 0) { - \Session::flash('error', 'There already is an entry for these parameters.'); - - return new \Limit; - } - // 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->repeat_freq = $data['period']; - if (!$limit->save()) { - \Session::flash('error', 'Could not save: ' . $limit->errors()->first()); - } - - return $limit; - } - - /** - * @param \Limit $limit - * - * @return bool - */ - public function destroy(\Limit $limit) - { - $limit->delete(); - - return true; - } - - /** - * @param \Budget $budget - * @param Carbon $start - * @param Carbon $end - * - * @return mixed - */ - public function getTJByBudgetAndDateRange(\Budget $budget, Carbon $start, Carbon $end) - { - $result = $budget->transactionjournals()->with('transactions')->after($start)->before($end)->get(); - - return $result; - - } - - /** - * @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; - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Limit/LimitRepositoryInterface.php b/app/lib/Firefly/Storage/Limit/LimitRepositoryInterface.php deleted file mode 100644 index 92a88a3279..0000000000 --- a/app/lib/Firefly/Storage/Limit/LimitRepositoryInterface.php +++ /dev/null @@ -1,70 +0,0 @@ -_user = \Auth::user(); - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importPiggybank(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error('No account available for piggy bank "' . $payload['data']['name'] . '". KILL!'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - - - /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ - $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); - $accounts->overruleUser($user); - - /* - * Maybe the piggy bank has already been imported - */ - $importEntry = $repository->findImportEntry($importMap, 'Piggybank', intval($payload['data']['id'])); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported piggy bank ' . $payload['data']['name']); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /* - * Try to find related piggybank: - */ - $piggyBank = $this->findByName($payload['data']['name']); - - /* - * Find an account (any account, really, at this point). - */ - $accountType = $accounts->findAccountType('Asset account'); - - /** @var Collection $set */ - $set = $accounts->getByAccountType($accountType); - - /* - * If there is an account to attach to this piggy bank, simply use that one. - */ - if ($set->count() > 0) { - /** @var \Account $account */ - $account = $set->first(); - $payload['data']['account_id'] = $account->id; - } else { - \Log::notice('No account available yet for piggy bank "' . $payload['data']['name'] . '".'); - if(\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - /* - * No existing piggy bank, create it: - */ - if (is_null($piggyBank)) { - $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; - $piggyBank = $this->store($payload['data']); - /* - * Store and fire event. - */ - $repository->store($importMap, 'Piggybank', intval($payload['data']['id']), $piggyBank->id); - \Log::debug('Imported piggy "' . $payload['data']['name'] . '".'); - \Event::fire('piggybanks.store', [$piggyBank]); - } else { - /* - * Already have a piggy bank with this name, we skip it. - */ - $repository->store($importMap, 'Piggybank', $payload['data']['id'], $piggyBank->id); - \Log::debug('Already imported piggy "' . $payload['data']['name'] . '".'); - } - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - 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.*']); - } - - public function countNonrepeating() - { - return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( - 'accounts.user_id', $this->_user->id - )->where('repeats', 0)->count(); - - } - - public function countRepeating() - { - return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( - 'accounts.user_id', $this->_user->id - )->where('repeats', 1)->count(); - } - - /** - * @param \Piggybank $piggyBank - * - * @return mixed|void - */ - public function destroy(\Piggybank $piggyBank) - { - $piggyBank->delete(); - - return true; - } - - /** - * @param $piggyBankId - * - * @return mixed - */ - public function find($piggyBankId) - { - return \Piggybank::leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where( - 'accounts.user_id', $this->_user->id - )->where('piggybanks.id', $piggyBankId)->first(['piggybanks.*']); - } - - /** - * @return mixed - */ - public function get() - { - $piggies = $this->_user->piggybanks()->with(['account', 'piggybankrepetitions'])->get(); - - return $piggies; - } - - /** - * @param \Account $account - * - * @return mixed|void - */ - public function leftOnAccount(\Account $account) - { - $balance = $account->balance(); - /** @var \Piggybank $p */ - foreach ($account->piggybanks()->get() as $p) { - $balance -= $p->currentRelevantRep()->currentamount; - } - - return $balance; - - } - - /** - * @param \Piggybank $piggyBank - * @param $amount - * - * @return bool|mixed - */ - public function modifyAmount(\Piggybank $piggyBank, $amount) - { - $rep = $piggyBank->currentRelevantRep(); - if (!is_null($rep)) { - $rep->currentamount += $amount; - $rep->save(); - } - - - return true; - - } - - /** - * @param $data - * - * @return \Piggybank - */ - public function store($data) - { - if (isset($data['targetdate']) && $data['targetdate'] == '') { - unset($data['targetdate']); - } - if (isset($data['reminder']) && $data['reminder'] == 'none') { - unset($data['reminder']); - } - if (isset($data['startdate']) && $data['startdate'] == '') { - unset($data['startdate']); - } - - /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ - $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); - $accounts->overruleUser($this->_user); - $account = isset($data['account_id']) ? $accounts->find($data['account_id']) : null; - - - $piggyBank = new \Piggybank($data); - - 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; - - } - - - if ($piggyBank->repeats && !isset($data['targetdate'])) { - $piggyBank->errors()->add('targetdate', 'Target date is mandatory!'); - \Log::error('PiggyBank create-error: ' . $piggyBank->errors()->first()); - - return $piggyBank; - } - if (!is_null($account)) { - $piggyBank->account()->associate($account); - } - $today = new Carbon; - - 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); - $firstReminder = new Carbon; - switch ($piggyBank->reminder) { - case 'day': - $firstReminder->addDays($reminderSkip); - break; - case 'week': - $firstReminder->addWeeks($reminderSkip); - break; - case 'month': - $firstReminder->addMonths($reminderSkip); - break; - case 'year': - $firstReminder->addYears($reminderSkip); - break; - default: - throw new FireflyException('Invalid reminder period'); - break; - } - if ($firstReminder > $piggyBank->targetdate) { - $piggyBank->errors()->add( - '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; - } - } - $piggyBank->save(); - } - - - return $piggyBank; - } - - /** - * @param \Piggybank $piggy - * @param $data - * - * @return mixed - */ - public function update(\Piggybank $piggy, $data) - { - /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ - $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); - $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->reminder_skip = $data['reminder_skip']; - $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; - - - foreach ($piggy->piggybankrepetitions()->get() as $rep) { - $rep->delete(); - } - - if ($piggy->repeats == 1) { - $piggy->rep_every = intval($data['rep_every']); - $piggy->rep_length = $data['rep_length']; - } - - if ($piggy->validate()) { - // check the things we check for new piggies - $piggy->save(); - } - - - return $piggy; - - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Piggybank/PiggybankRepositoryInterface.php b/app/lib/Firefly/Storage/Piggybank/PiggybankRepositoryInterface.php deleted file mode 100644 index 5e9af3409c..0000000000 --- a/app/lib/Firefly/Storage/Piggybank/PiggybankRepositoryInterface.php +++ /dev/null @@ -1,95 +0,0 @@ -_user = \Auth::user(); - } - - /** - * @param \RecurringTransaction $recurringTransaction - * - * @return bool|mixed - */ - public function destroy(\RecurringTransaction $recurringTransaction) - { - $recurringTransaction->delete(); - - return true; - } - - /** - * @return mixed - */ - public function get() - { - return $this->_user->recurringtransactions()->get(); - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importPredictable(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - /* - * maybe the recurring transaction is already imported: - */ - $oldId = intval($payload['data']['id']); - $description = $payload['data']['description']; - $importEntry = $repository->findImportEntry($importMap, 'RecurringTransaction', $oldId); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported recurring transaction #' . $payload['data']['id']); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - // try to find related recurring transaction: - $recurringTransaction = $this->findByName($payload['data']['description']); - if (is_null($recurringTransaction)) { - $amount = floatval($payload['data']['amount']); - $pct = intval($payload['data']['pct']); - - $set = [ - 'name' => $description, - 'match' => join(',', explode(' ', $description)), - 'amount_min' => $amount * ($pct / 100) * -1, - 'amount_max' => $amount * (1 + ($pct / 100)) * -1, - 'date' => date('Y-m-') . $payload['data']['dom'], - 'repeat_freq' => 'monthly', - 'active' => intval($payload['data']['inactive']) == 1 ? 0 : 1, - 'automatch' => 1, - ]; - - $recurringTransaction = $this->store($set); - $this->store($importMap, 'RecurringTransaction', $oldId, $recurringTransaction->id); - \Log::debug('Imported predictable ' . $description); - } else { - $this->store($importMap, 'RecurringTransaction', $oldId, $recurringTransaction->id); - \Log::debug('Already had predictable ' . $description); - } - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - public function findByName($name) - { - return $this->_user->recurringtransactions()->where('name', 'LIKE', '%' . $name . '%')->first(); - } - - /** - * @param $data - * - * @return MessageBag - */ - public function store($data) - { - $messageBag = new MessageBag; - $recurringTransaction = new \RecurringTransaction( - [ - 'user_id' => $this->_user->id, - 'name' => $data['name'], - 'match' => join(' ', explode(',', $data['match'])), - 'amount_max' => floatval($data['amount_max']), - 'amount_min' => floatval($data['amount_min']), - 'date' => new Carbon($data['date']), - 'active' => isset($data['active']) ? intval($data['active']) : 0, - 'automatch' => isset($data['automatch']) ? intval($data['automatch']) : 0, - 'skip' => isset($data['skip']) ? intval($data['skip']) : 0, - 'repeat_freq' => $data['repeat_freq'], - ] - ); - - // unique name? - $count = $this->_user->recurringtransactions()->whereName($data['name'])->count(); - if ($count > 0) { - $messageBag->add('name', 'A recurring transaction with this name already exists.'); - return $messageBag; - } - - // both amounts zero?: - if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) { - $messageBag->add('amount_max', 'Amount max and min cannot both be zero.'); - return $messageBag; - } - - if ($recurringTransaction->amount_max < $recurringTransaction->amount_min) { - $messageBag->add('amount_max', 'Amount max must be more than amount min.'); - return $messageBag; - } - - if ($recurringTransaction->amount_min > $recurringTransaction->amount_max) { - $messageBag->add('amount_max', 'Amount min must be less than amount max.'); - return $messageBag; - } - - if ($recurringTransaction->validate()) { - $recurringTransaction->save(); - } else { - $messageBag = $recurringTransaction->errors(); - } - - return $messageBag; - } - - /** - * @param \RecurringTransaction $recurringTransaction - * @param $data - * - * @return MessageBag - */ - public function update(\RecurringTransaction $recurringTransaction, $data) - { - $messageBag = new MessageBag; - $recurringTransaction->name = $data['name']; - $recurringTransaction->match = join(' ', explode(',', $data['match'])); - $recurringTransaction->amount_max = floatval($data['amount_max']); - $recurringTransaction->amount_min = floatval($data['amount_min']); - - // both amounts zero: - if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) { - $messageBag->add('amount_max', 'Amount max and min cannot both be zero.'); - - return $messageBag; - } - $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()) { - $recurringTransaction->save(); - } else { - $messageBag = $recurringTransaction->errors(); - } - - return $messageBag; - - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/RecurringTransaction/RecurringTransactionRepositoryInterface.php b/app/lib/Firefly/Storage/RecurringTransaction/RecurringTransactionRepositoryInterface.php deleted file mode 100644 index 0e753f3e3d..0000000000 --- a/app/lib/Firefly/Storage/RecurringTransaction/RecurringTransactionRepositoryInterface.php +++ /dev/null @@ -1,64 +0,0 @@ -_user = $user; - return true; - } - - protected $_user = null; - - /** - * - */ - public function __construct() - { - $this->_user = \Auth::user(); - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Reminder/ReminderRepositoryInterface.php b/app/lib/Firefly/Storage/Reminder/ReminderRepositoryInterface.php deleted file mode 100644 index 05e6c77a54..0000000000 --- a/app/lib/Firefly/Storage/Reminder/ReminderRepositoryInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -app->bind( - 'Firefly\Storage\User\UserRepositoryInterface', - 'Firefly\Storage\User\EloquentUserRepository' - ); - $this->app->bind( - '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\RecurringTransaction\RecurringTransactionRepositoryInterface', - 'Firefly\Storage\RecurringTransaction\EloquentRecurringTransactionRepository' - ); - - $this->app->bind( - 'Firefly\Storage\Reminder\ReminderRepositoryInterface', - 'Firefly\Storage\Reminder\EloquentReminderRepository' - ); - - $this->app->bind( - 'Firefly\Storage\Account\AccountRepositoryInterface', - 'Firefly\Storage\Account\EloquentAccountRepository' - ); - $this->app->bind( - 'Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface', - 'Firefly\Storage\TransactionJournal\EloquentTransactionJournalRepository' - ); - - $this->app->bind( - 'Firefly\Storage\Limit\LimitRepositoryInterface', - 'Firefly\Storage\Limit\EloquentLimitRepository' - ); - - $this->app->bind( - 'Firefly\Storage\Budget\BudgetRepositoryInterface', - 'Firefly\Storage\Budget\EloquentBudgetRepository' - ); - $this->app->bind( - 'Firefly\Storage\Category\CategoryRepositoryInterface', - 'Firefly\Storage\Category\EloquentCategoryRepository' - ); - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Transaction/EloquentTransactionRepository.php b/app/lib/Firefly/Storage/Transaction/EloquentTransactionRepository.php deleted file mode 100644 index a4307a2e50..0000000000 --- a/app/lib/Firefly/Storage/Transaction/EloquentTransactionRepository.php +++ /dev/null @@ -1,32 +0,0 @@ -_user = \Auth::user(); - } - - /** - * @param \User $user - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/Transaction/TransactionRepositoryInterface.php b/app/lib/Firefly/Storage/Transaction/TransactionRepositoryInterface.php deleted file mode 100644 index 314f72b0c4..0000000000 --- a/app/lib/Firefly/Storage/Transaction/TransactionRepositoryInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -_user = \Auth::user(); - } - - /** - * Get them ALL - * - * @return Collection - */ - public function get() { - return $this->_user->transactionjournals()->with('transactions')->get(); - } - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importTransfer(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - - if ($job->attempts() > 10) { - \Log::error('Never found accounts for transfer "' . $payload['data']['description'] . '". KILL!'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /** @var \Firefly\Helper\Controllers\TransactionInterface $transactions */ - $transactions = \App::make('Firefly\Helper\Controllers\TransactionInterface'); - $transactions->overruleUser($this->_user); - - /* - * Prep some variables from the payload: - */ - $fromAccountId = intval($payload['data']['accountfrom_id']); - $toAccountId = intval($payload['data']['accountto_id']); - $description = $payload['data']['description']; - $transferId = intval($payload['data']['id']); - $amount = floatval($payload['data']['amount']); - $date = new Carbon($payload['data']['date']); - - /* - * maybe Journal is already imported: - */ - $importEntry = $repository->findImportEntry($importMap, 'Transfer', $transferId); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported transfer ' . $description); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /* - * Find the 'from' account: - */ - $oldFromAccountEntry = $repository->findImportEntry($importMap, 'Account', $fromAccountId); - - /* - * Find the 'to' account: - */ - $oldToAccountEntry = $repository->findImportEntry($importMap, 'Account', $toAccountId); - - /* - * Import transfer: - */ - $set = [ - 'account_from_id' => $oldFromAccountEntry->new, - 'account_to_id' => $oldToAccountEntry->new, - 'amount' => $amount, - 'description' => $description, - 'date' => $date->format('Y-m-d'), - 'category' => '', - 'what' => 'transfer', - 'return_journal' => true - ]; - $returnSet = $transactions->store($set); - $journal = $returnSet['journal']; - - /* - * Validate the store action: - */ - if ($journal instanceof MessageBag) { - /* - * It's a message bag; clearly something went wrong. - */ - \Log::notice('Could not import TJ "' . $description . '": ' . $journal->first()); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } else if ($journal instanceof \TransactionJournal && $journal->errors()->count() > 0) { - /* - * It's a journal but it still failed somehow. - */ - \Log::notice('Could not import TJ "' . $description . '": ' . $journal->errors()->first()); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - $repository->store($importMap, 'Transfer', $transferId, $journal->id); - \Log::debug('Imported transfer "' . $description . '" (' . $amount . ') (' . $date->format('Y-m-d') . ')'); - - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed. - - } - - /** - * @param \User $user - * - * @return mixed|void - */ - public function overruleUser(\User $user) - { - $this->_user = $user; - return true; - } - - /** - * @param array $data - * - * @return \TransactionJournal - */ - public function store(array $data) - { - /* - * Create the journal and fill relevant fields. - */ - $journal = new \TransactionJournal; - $journal->description = trim($data['description']); - $journal->date = new Carbon($data['date']); - $journal->user_id = $this->_user->id; - $journal->completed = false; - - /* - * Find the more complex fields and fill those: - */ - $currency = \TransactionCurrency::where('code', 'EUR')->first(); - $journal->transaction_currency_id = $currency->id; - $transactionType = \TransactionType::where('type', $data['what'])->first(); - $journal->transaction_type_id = $transactionType->id; - - /* - * Validate & save journal - */ - $journal->validate(); - $journal->save(); - - /* - * Return regardless. - */ - return $journal; - } - - /** - * @param \TransactionJournal $journal - * @param \Account $account - * @param $amount - * - * @return \Transaction|null - */ - public function saveTransaction(\TransactionJournal $journal, \Account $account, $amount) - { - $transaction = new \Transaction; - $transaction->account_id = $account->id; - $transaction->transaction_journal_id = $journal->id; - $transaction->amount = $amount; - if ($transaction->validate()) { - $transaction->save(); - } - return $transaction; - - } - - - /** - * @param Job $job - * @param array $payload - * - * @return mixed - */ - public function importTransaction(Job $job, array $payload) - { - /** @var \Firefly\Storage\Import\ImportRepositoryInterface $repository */ - $repository = \App::make('Firefly\Storage\Import\ImportRepositoryInterface'); - - /** @var \Importmap $importMap */ - $importMap = $repository->findImportmap($payload['mapID']); - $user = $importMap->user; - $this->overruleUser($user); - - if ($job->attempts() > 10) { - \Log::error('Never found asset account for transaction "' . $payload['data']['description'] . '". KILL!'); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */ - $accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface'); - $accounts->overruleUser($user); - - /** @var \Firefly\Helper\Controllers\TransactionInterface $transactions */ - $transactions = \App::make('Firefly\Helper\Controllers\TransactionInterface'); - $transactions->overruleUser($this->_user); - - - /* - * Prep some vars coming out of the pay load: - */ - $amount = floatval($payload['data']['amount']); - $date = new Carbon($payload['data']['date']); - $description = $payload['data']['description']; - $transactionId = intval($payload['data']['id']); - $accountId = intval($payload['data']['account_id']); - - /* - * maybe Journal is already imported: - */ - $importEntry = $repository->findImportEntry($importMap, 'Transaction', $transactionId); - - /* - * if so, delete job and return: - */ - if (!is_null($importEntry)) { - \Log::debug('Already imported transaction ' . $description); - - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - } - - /* - * Find or create the "import account" which is used because at this point, Firefly - * doesn't know which beneficiary (expense account) should be connected to this transaction. - */ - $accountType = $accounts->findAccountType('Import account'); - $importAccount = $accounts->firstOrCreate( - [ - 'account_type_id' => $accountType->id, - 'name' => 'Import account', - 'user_id' => $user->id, - 'active' => 1, - ] - ); - unset($accountType); - - /* - * Find the asset account this transaction is paid from / paid to: - */ - $accountEntry = $repository->findImportEntry($importMap, 'Account', $accountId); - - /* - * Prep some data for the import routine: - */ - $set = [ - 'category' => '', - 'description' => $description, - 'date' => $date->format('Y-m-d'), - 'return_journal' => true, - 'account_id' => $accountEntry->new - ]; - - - /* - * If the amount is less than zero, we move money to the $importAccount. Otherwise, - * we move it from the $importAccount. - */ - - if ($amount < 0) { - // if amount is less than zero, move to $importAccount - $set['what'] = 'withdrawal'; - $set['expense_account'] = $importAccount->name; - } else { - $set['what'] = 'deposit'; - $set['revenue_account'] = $importAccount->name; - } - - /* - * Modify the amount so it will work with or new transaction journal structure. - */ - $set['amount'] = $amount < 0 ? $amount * -1 : $amount; - - /* - * Import it: - */ - $returnSet = $transactions->store($set); - $journal = $returnSet['journal']; - - /* - * Validate the store action: - */ - if ($journal instanceof MessageBag) { - - /* - * It's a message bag; clearly something went wrong. - */ - \Log::notice('Could not import transfer "' . $description . '": ' . $journal->first()); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } else if ($journal instanceof \TransactionJournal && $journal->errors()->count() > 0) { - /* - * It's a journal but it still failed somehow. - */ - \Log::notice('Could not import transfer "' . $description . '": ' . $journal->errors()->first()); - if (\Config::get('queue.default') == 'sync') { - $importMap->jobsdone++; - $importMap->save(); - $job->delete(); // count fixed - } else { - $job->release(300); // proper release. - } - return; - } - - $repository->store($importMap, 'Transaction', $transactionId, $journal->id); - \Log::debug('Imported transaction "' . $description . '" (' . $amount . ') (' . $date->format('Y-m-d') . ')'); - - // update map: - $importMap->jobsdone++; - $importMap->save(); - - $job->delete(); // count fixed - return; - - } - - /** - * @param $journalId - * - * @return mixed - */ - public function find($journalId) - { - 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(); - } - - /** - * @param \Account $account - * @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 = $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.*']); - - return $query; - } - /** - * @param \TransactionJournal $journal - * @param $data - * - * @return mixed|\TransactionJournal - * @throws \Firefly\Exception\FireflyException - */ - public function update(\TransactionJournal $journal, $data) - { - /* - * Update the basic fields: - */ - $journal->description = trim($data['description']); - $journal->date = new Carbon($data['date']); - - /* - * Validate & save journal - */ - $journal->validate(); - $journal->save(); - - /* - * Return regardless. - */ - return $journal; - - - } -// /* -// * Grab some of the repositories we need: -// */ -// /** @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']); -// -// // remove previous category, if any: -// if (!is_null($journal->categories()->first())) { -// $journal->categories()->detach($journal->categories()->first()->id); -// } -// // remove previous budget, if any: -// if (!is_null($journal->budgets()->first())) { -// $journal->budgets()->detach($journal->budgets()->first()->id); -// } -// // remove previous piggy bank, if any: -// -// -// $category = isset($data['category']) ? $catRepository->findByName($data['category']) : null; -// if (!is_null($category)) { -// $journal->categories()->attach($category); -// } -// // update the amounts: -// $transactions = $journal->transactions()->orderBy('amount', 'ASC')->get(); -// -// // remove previous piggy bank, if any: -// /** @var \Transaction $transaction */ -// foreach ($transactions as $transaction) { -// if (!is_null($transaction->piggybank()->first())) { -// $transaction->piggybank_id = null; -// $transaction->save(); -// } -// } -// unset($transaction); -// -// $transactions[0]->amount = $amount * -1; -// $transactions[1]->amount = $amount; -// -// // switch on type to properly change things: -// $fireEvent = false; -// switch ($journal->transactiontype->type) { -// case 'Withdrawal': -// // means transaction[0] is the users account. -// $account = $accountRepository->find($data['account_id']); -// $beneficiary = $accountRepository->createOrFindBeneficiary($data['beneficiary']); -// $transactions[0]->account()->associate($account); -// $transactions[1]->account()->associate($beneficiary); -// -// // do budget: -// $budget = $budRepository->find($data['budget_id']); -// if (!is_null($budget)) { -// $journal->budgets()->attach($budget); -// } -// -// break; -// case 'Deposit': -// // means transaction[0] is the beneficiary. -// $account = $accountRepository->find($data['account_id']); -// $beneficiary = $accountRepository->createOrFindBeneficiary($data['beneficiary']); -// $journal->transactions[0]->account()->associate($beneficiary); -// $journal->transactions[1]->account()->associate($account); -// break; -// case 'Transfer': -// // means transaction[0] is account that sent the money (from). -// /** @var \Account $fromAccount */ -// $fromAccount = $accountRepository->find($data['account_from_id']); -// /** @var \Account $toAccount */ -// $toAccount = $accountRepository->find($data['account_to_id']); -// $journal->transactions[0]->account()->associate($fromAccount); -// $journal->transactions[1]->account()->associate($toAccount); -// -// // 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 */ -// $piggyBank = $piggyRepository->find(intval($data['piggybank_id'])); -// -// // loop transactions and re-attach the piggy bank: -// -// if ($piggyBank) { -// -// $connected = false; -// foreach ($journal->transactions()->get() as $transaction) { -// if ($transaction->account_id == $piggyBank->account_id) { -// $connected = true; -// $transaction->piggybank()->associate($piggyBank); -// $transaction->save(); -// $fireEvent = true; -// 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' -// ); -// } -// } -// } -// -// -// break; -// default: -// throw new FireflyException('Cannot edit this!'); -// break; -// } -// -// $transactions[0]->save(); -// $transactions[1]->save(); -// if ($journal->validate()) { -// $journal->save(); -// } -// if ($fireEvent) { -// \Event::fire('piggybanks.updateRelatedTransfer', [$piggyBank]); -// } -// -// return $journal; -// -// -// } - - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php b/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php deleted file mode 100644 index 2d01a7884d..0000000000 --- a/app/lib/Firefly/Storage/TransactionJournal/TransactionJournalRepositoryInterface.php +++ /dev/null @@ -1,88 +0,0 @@ -first(); - } - - /** - * @param $reset - * - * @return mixed - */ - public function findByReset($reset) - { - return \User::where('reset', $reset)->first(); - } - - /** - * @param $array - * - * @return bool|\User - */ - public function register($array) - { - $user = new \User; - $user->email = isset($array['email']) ? $array['email'] : null; - $user->migrated = 0; - $user->reset = \Str::random(32); - $user->password = \Hash::make(\Str::random(12)); - - if (!$user->save()) { - \Log::error('Invalid user'); - \Session::flash('error', 'Input invalid, please try again: ' . $user->errors()->first()); - - return false; - } - $user->save(); - - return $user; - } - - /** - * @param \User $user - * @param $password - * - * @return bool - */ - public function updatePassword(\User $user, $password) - { - /** @noinspection PhpUndefinedFieldInspection */ - $user->password = $password; - /** @noinspection PhpUndefinedMethodInspection */ - $user->forceSave(); - - return true; - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Storage/User/UserRepositoryInterface.php b/app/lib/Firefly/Storage/User/UserRepositoryInterface.php deleted file mode 100644 index d74b9cbae9..0000000000 --- a/app/lib/Firefly/Storage/User/UserRepositoryInterface.php +++ /dev/null @@ -1,43 +0,0 @@ -listen('budgets.destroy', 'Firefly\Trigger\Budgets\EloquentBudgetTrigger@destroy'); -// $events->listen('budgets.store', 'Firefly\Trigger\Budgets\EloquentBudgetTrigger@store'); -// $events->listen('budgets.update', 'Firefly\Trigger\Budgets\EloquentBudgetTrigger@update'); - - } - - /** - * Same. Doesn't do much. - * - * @param \Budget $budget - * - * @return bool - */ - public function update(\Budget $budget) - { - return true; - - } -} diff --git a/app/lib/Firefly/Trigger/Journals/EloquentJournalTrigger.php b/app/lib/Firefly/Trigger/Journals/EloquentJournalTrigger.php deleted file mode 100644 index cbb5196fae..0000000000 --- a/app/lib/Firefly/Trigger/Journals/EloquentJournalTrigger.php +++ /dev/null @@ -1,64 +0,0 @@ -user()->first()->recurringtransactions()->get(); - $result = []; - /* - * Prep vars - */ - $description = strtolower($journal->description); - $result = [0 => 0]; - - /** @var \RecurringTransaction $recurring */ - foreach ($set as $recurring) { - \Event::fire('recurring.rescan', [$recurring, $journal]); - } - - 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; - - } - -} \ No newline at end of file diff --git a/app/lib/Firefly/Trigger/Limits/EloquentLimitTrigger.php b/app/lib/Firefly/Trigger/Limits/EloquentLimitTrigger.php deleted file mode 100644 index 2633684c14..0000000000 --- a/app/lib/Firefly/Trigger/Limits/EloquentLimitTrigger.php +++ /dev/null @@ -1,133 +0,0 @@ -where('components.user_id', \Auth::user()->id) - ->where('limits.repeats', 1) - ->get(['limits.*']); - } else { - $limits = []; - } - - /** @var \Limit $limit */ - foreach ($limits as $limit) { - // the limit repeats, and there should be at least one repetition already. - /** @var \LimitRepetition $primer */ - $primer = $limit->limitrepetitions()->orderBy('startdate', 'DESC')->first(); - $today = new Carbon; - $start = clone $primer->enddate; - // from the primer onwards. - while ($start <= $today) { - $start->addDay(); - $end = clone $start; - - // add period to determin end of limitrepetition: - switch ($limit->repeat_freq) { - case 'daily': - $end->addDay(); - break; - case 'weekly': - $end->addWeek(); - break; - case 'monthly': - $end->addMonth(); - break; - case 'quarterly': - $end->addMonths(3); - break; - case 'half-year': - $end->addMonths(6); - break; - case 'yearly': - $end->addYear(); - break; - } - $end->subDay(); - // create repetition: - $limit->createRepetition($start); - $start = clone $end; - } - } - } - - /** - * @param \Limit $limit - * - * @return bool - */ - public function destroy(\Limit $limit) - { - return true; - - } - - /** - * @param \LimitRepetition $repetition - */ - public function madeRepetition(\LimitRepetition $repetition) - { - \Log::debug('TRIGGER: Created a limit repetition (#' . $repetition->id . ')'); - } - - /** - * @param \Limit $limit - * - * @return bool - */ - public function store(\Limit $limit) - { - // create a repetition (repetitions) for this limit (we ignore "repeats"): - $limit->createRepetition($limit->startdate); - - return true; - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - //$events->listen('budgets.change', 'Firefly\Trigger\Limits\EloquentLimitTrigger@updateLimitRepetitions'); -// $events->listen('limits.destroy', 'Firefly\Trigger\Limits\EloquentLimitTrigger@destroy'); -// $events->listen('limits.store', 'Firefly\Trigger\Limits\EloquentLimitTrigger@store'); -// $events->listen('limits.update', 'Firefly\Trigger\Limits\EloquentLimitTrigger@update'); -// $events->listen('limits.check', 'Firefly\Trigger\Limits\EloquentLimitTrigger@checkRepeatingLimits'); -// $events->listen('limits.repetition', 'Firefly\Trigger\Limits\EloquentLimitTrigger@madeRepetition'); - //\Event::fire('limits.repetition', [$repetition]); - - } - - /** - * @param \Limit $limit - * - * @return bool - */ - public function update(\Limit $limit) - { - // remove and recreate limit repetitions. - // if limit is not repeating, simply update the repetition to match the limit, - // even though deleting everything is easier. - $limit->createRepetition($limit->startdate); - - return true; - } -} diff --git a/app/lib/Firefly/Trigger/Piggybanks/EloquentPiggybankTrigger.php b/app/lib/Firefly/Trigger/Piggybanks/EloquentPiggybankTrigger.php deleted file mode 100644 index 5a51efe653..0000000000 --- a/app/lib/Firefly/Trigger/Piggybanks/EloquentPiggybankTrigger.php +++ /dev/null @@ -1,239 +0,0 @@ -piggybanks()->where('repeats', 1)->get(); - } else { - $piggies = []; - } - - \Log::debug('Now in checkRepeatingPiggies with ' . count($piggies) . ' piggies found.'); - - /** @var \Piggybank $piggyBank */ - foreach ($piggies as $piggyBank) { - \Log::debug('Now working on ' . $piggyBank->name); - - /* - * Get the latest repetition, see if Firefly needs to create more. - */ - /** @var \PiggybankRepetition $primer */ - $primer = $piggyBank->piggybankrepetitions()->orderBy('targetdate', 'DESC')->first(); - \Log::debug('Last target date is: ' . $primer->targetdate); - - $today = new Carbon; - - // the next repetition must be created starting at the day after the target date of the previous one. - /* - * A repeated expense runs from day 1 to day X. Since it repeats, the next repetition starts at day X+1 - * until however often the repeated expense is set to repeat: a month, a week, a year. - */ - $start = clone $primer->targetdate; - $start->addDay(); - - while ($start <= $today) { - \Log::debug('Looping! Start is: ' . $start); - - // to get to the end of the current repetition, we switch on the piggy bank's - // repetition period: - $end = clone $start; - switch ($piggyBank->rep_length) { - case 'day': - $end->addDays($piggyBank->rep_every); - break; - case 'week': - $end->addWeeks($piggyBank->rep_every); - break; - case 'month': - $end->addMonths($piggyBank->rep_every); - break; - case 'year': - $end->addYears($piggyBank->rep_every); - break; - } - $end->subDay(); - - // create repetition: - $piggyBank->createRepetition($start, $end); - - $start = clone $end; - $start->addDay(); - - - } - - } - } - - /** - * @param \Piggybank $piggyBank - * @param \TransactionJournal $journal - * @param \Transaction $transaction - * - * @return bool - */ - public function createRelatedTransfer( - \Piggybank $piggyBank, \TransactionJournal $journal, \Transaction $transaction - ) { - $repetition = $piggyBank->repetitionForDate($journal->date); - if (!is_null($repetition)) { - // get the amount transferred TO this - $amount = floatval($transaction->amount); - $repetition->currentamount += $amount; - $repetition->save(); - } else { - \Session::flash('warning', 'Cannot add transfer to piggy, outside of scope.'); - } - - return true; - } - - /** - * @param \Piggybank $piggyBank - * @param $amount - */ - public function modifyAmountAdd(\Piggybank $piggyBank, $amount) - { - $rep = $piggyBank->currentRelevantRep(); - $today = new Carbon; - - // create event: - $event = new \PiggybankEvent; - $event->date = new Carbon; - $event->amount = $amount; - $event->piggybank()->associate($piggyBank); - - // for future / past repetitions. - if (!($rep->startdate >= $today && $rep->targetdate <= $today)) { - $event->date = $rep->startdate; - } - - - $event->save(); - } - - /** - * @param \Piggybank $piggyBank - * @param $amount - */ - public function modifyAmountRemove(\Piggybank $piggyBank, $amount) - { - // create event: - $event = new \PiggybankEvent; - $event->date = new Carbon; - $event->amount = $amount; - $event->piggybank()->associate($piggyBank); - $event->save(); - } - - /** - * This method is called when a piggy bank or repeated expense is created. It will create the first - * repetition which by default is equal to the PB / RE itself. After that, other triggers will take over. - * - * @param \Piggybank $piggyBank - * - * @return bool - */ - public function store(\Piggybank $piggyBank) - { - $piggyBank->createRepetition($piggyBank->startdate, $piggyBank->targetdate); - - return true; - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { -// $events->listen('piggybanks.modifyAmountAdd', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@modifyAmountAdd'); -// $events->listen('piggybanks.modifyAmountRemove', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@modifyAmountRemove'); -// $events->listen('piggybanks.store', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@store'); -// $events->listen('piggybanks.update', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@update'); -// $events->listen('piggybanks.createRelatedTransfer', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@createRelatedTransfer'); -// $events->listen('piggybanks.updateRelatedTransfer', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@updateRelatedTransfer'); -// $events->listen('piggybanks.storepiggybanks.check', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@checkRepeatingPiggies'); - - } - - /** - * When the user updates a piggy bank the repetitions, past and now, may be wrong. The best bet - * would be to delete everything and start over, but that also means past repetitions will be gone. - * - * Instead, we have disabled changing the dates when the piggy bank is repeating: a repeated expense cannot - * have its dates changed. This will prevent many problems I don't want to deal with. - * - * @param \Piggybank $piggyBank - */ - public function update(\Piggybank $piggyBank) - { - // delete all repetitions: - foreach ($piggyBank->piggybankrepetitions()->get() as $rep) { - - $rep->delete(); - } - unset($rep); - - // trigger "new" piggy bank to recreate them. - \Event::fire('piggybanks.store', [$piggyBank]); - - - // loop the repetitions and update them according to the events and the transactions: - foreach ($piggyBank->piggybankrepetitions()->get() as $rep) { - // SUM for transactions - $query = \Transaction::where('piggybank_id', $piggyBank->id)->leftJoin( - 'transaction_journals', 'transaction_journals.id', '=', - 'transactions.transaction_journal_id' - ); - if (!is_null($rep->startdate)) { - $query->where('transaction_journals.date', '>=', $rep->startdate->format('Y-m-d')); - } - if (!is_null($rep->targetdate)) { - $query->where( - 'transaction_journals.date', '<=', $rep->targetdate->format('Y-m-d') - ); - } - $sum = $query->sum('transactions.amount'); - - // get events for piggy bank, save those as well: - $eventSumQuery = $piggyBank->piggybankevents(); - if (!is_null($rep->startdate)) { - $eventSumQuery->where('date', '>=', $rep->startdate->format('Y-m-d')); - } - if (!is_null($rep->targetdate)) { - $eventSumQuery->where('date', '<=', $rep->targetdate->format('Y-m-d')); - } - $eventSum = floatval($eventSumQuery->sum('amount')); - $rep->currentamount = floatval($sum) + $eventSum; - $rep->save(); - - } - } - - public function updateRelatedTransfer(\Piggybank $piggyBank) - { - // fire the "update" trigger which should handle things just fine: - \Event::fire('piggybanks.update', [$piggyBank]); - } - - -} \ No newline at end of file diff --git a/app/lib/Firefly/Trigger/Recurring/EloquentRecurringTrigger.php b/app/lib/Firefly/Trigger/Recurring/EloquentRecurringTrigger.php deleted file mode 100644 index b29167bb48..0000000000 --- a/app/lib/Firefly/Trigger/Recurring/EloquentRecurringTrigger.php +++ /dev/null @@ -1,111 +0,0 @@ -match); - $description = strtolower($journal->description); - - /* - * Attach expense account to description for more narrow matching. - */ - $transactions = $journal->transactions()->get(); - /** @var \Transaction $transaction */ - foreach ($transactions as $transaction) { - /** @var \Account $account */ - $account = $transaction->account()->first(); - /** @var \AccountType $type */ - $type = $account->accountType()->first(); - if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') { - $description .= ' ' . strtolower($account->name); - } - } - - $count = 0; - foreach ($matches as $word) { - if (!(strpos($description, strtolower($word)) === false)) { - $count++; - } - } - if ($count >= count($matches)) { - $wordMatch = true; - } - - /* - * Match amount. - */ - - $amountMatch = false; - if (count($transactions) > 1) { - - $amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount)); - $min = floatval($recurring->amount_min); - $max = floatval($recurring->amount_max); - if ($amount >= $min && $amount <= $max) { - $amountMatch = true; - } - } - - /* - * If both, update! - */ - if ($wordMatch && $amountMatch) { - $journal->recurringTransaction()->associate($recurring); - $journal->save(); - } - - } - - /** - * Trigger! - * - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - //$events->listen('recurring.rescan', 'Firefly\Trigger\Recurring\EloquentRecurringTrigger@rescan'); - } - - /** - * @param \RecurringTransaction $recurring - */ - public function update(\RecurringTransaction $recurring) - { - } -} \ No newline at end of file diff --git a/app/lib/Firefly/Validation/FireflyValidator.php b/app/lib/Firefly/Validation/FireflyValidator.php deleted file mode 100644 index cb3bb93d8e..0000000000 --- a/app/lib/Firefly/Validation/FireflyValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -app->validator->resolver( - function ($translator, $data, $rules, $messages) { - return new FireflyValidator($translator, $data, $rules, $messages); - } - ); - } - - public function register() - { - } -} \ No newline at end of file diff --git a/app/lib/FireflyIII/Chart/Chart.php b/app/lib/FireflyIII/Chart/Chart.php new file mode 100644 index 0000000000..302a014c5b --- /dev/null +++ b/app/lib/FireflyIII/Chart/Chart.php @@ -0,0 +1,75 @@ +on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0); + } + ) + ->leftJoin( + 'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' + ) + ->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->before($end) + ->after($start) + ->where('transaction_types.type', 'Withdrawal') + ->groupBy('categories.id') + ->orderBy('sum', 'DESC') + ->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]); + } + + /** + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getRecurringSummary(Carbon $start, Carbon $end) + { + return \RecurringTransaction:: + leftJoin( + 'transaction_journals', function (JoinClause $join) use ($start, $end) { + $join->on('recurring_transactions.id', '=', 'transaction_journals.recurring_transaction_id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')); + } + ) + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '>', 0); + } + ) + ->where('active', 1) + ->groupBy('recurring_transactions.id') + ->get( + ['recurring_transactions.id', 'recurring_transactions.name', 'transaction_journals.description', + 'transaction_journals.id as journalId', + \DB::Raw('SUM(`recurring_transactions`.`amount_min` + `recurring_transactions`.`amount_max`) / 2 as `averageAmount`'), + 'transactions.amount AS actualAmount'] + ); + } +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Chart/ChartInterface.php b/app/lib/FireflyIII/Chart/ChartInterface.php new file mode 100644 index 0000000000..7b29e3c9e9 --- /dev/null +++ b/app/lib/FireflyIII/Chart/ChartInterface.php @@ -0,0 +1,31 @@ +reminder)) { + $this->reminder = $this->repetition->piggybank->reminders()->where('startdate', $this->getStartdate()->format('Y-m-d'))->where( + 'enddate', $this->getTargetdate()->format('Y-m-d') + )->first(); + } + return $this->reminder; } @@ -44,22 +52,6 @@ class PiggybankPart $this->reminder = $reminder; } - /** - * @return \PiggybankRepetition - */ - public function getRepetition() - { - return $this->repetition; - } - - /** - * @param \PiggybankRepetition $repetition - */ - public function setRepetition($repetition) - { - $this->repetition = $repetition; - } - /** * @return Carbon */ @@ -92,11 +84,33 @@ class PiggybankPart $this->targetdate = $targetdate; } + /** + * @return \PiggybankRepetition + */ + public function getRepetition() + { + return $this->repetition; + } + + /** + * @param \PiggybankRepetition $repetition + */ + public function setRepetition($repetition) + { + $this->repetition = $repetition; + } + + /** + * @return bool + */ public function hasReminder() { return !is_null($this->reminder); } + /** + * @return float|int + */ public function percentage() { if ($this->getCurrentamount() < $this->getCumulativeAmount()) { @@ -129,22 +143,6 @@ class PiggybankPart $this->currentamount = $currentamount; } - /** - * @return float - */ - public function getAmountPerBar() - { - return $this->amountPerBar; - } - - /** - * @param float $amountPerBar - */ - public function setAmountPerBar($amountPerBar) - { - $this->amountPerBar = $amountPerBar; - } - /** * @return float */ @@ -161,7 +159,21 @@ class PiggybankPart $this->cumulativeAmount = $cumulativeAmount; } + /** + * @return float + */ + public function getAmountPerBar() + { + return $this->amountPerBar; + } + /** + * @param float $amountPerBar + */ + public function setAmountPerBar($amountPerBar) + { + $this->amountPerBar = $amountPerBar; + } } \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Account.php b/app/lib/FireflyIII/Database/Account/Account.php similarity index 82% rename from app/lib/FireflyIII/Database/Account.php rename to app/lib/FireflyIII/Database/Account/Account.php index 3e26eb3aaf..1318bc040d 100644 --- a/app/lib/FireflyIII/Database/Account.php +++ b/app/lib/FireflyIII/Database/Account/Account.php @@ -1,19 +1,21 @@ findByWhat('initial'); @@ -182,8 +184,8 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface */ $balance = floatval($data['openingbalance']); $date = new Carbon($data['openingbalancedate']); - /** @var \FireflyIII\Database\TransactionJournal $tj */ - $tj = \App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $tj */ + $tj = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); if ($balance < 0) { // first transaction draws money from the new account to the opposing $from = $account; @@ -213,39 +215,56 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface } /** - * @param \Eloquent $model + * @param Eloquent $model * * @return bool */ - public function destroy(\Eloquent $model) + public function destroy(Eloquent $model) { // delete journals: $journals = \TransactionJournal::whereIn( 'id', function ($query) use ($model) { - $query->select('transaction_journal_id') - ->from('transactions')->whereIn( - 'account_id', function ($query) use ($model) { - $query - ->select('id') - ->from('accounts') - ->where( + $query->select('transaction_journal_id') + ->from('transactions')->whereIn( + 'account_id', function ($query) use ($model) { + $query + ->select('id') + ->from('accounts') + ->where( + function ($q) use ($model) { + $q->where('id', $model->id); + $q->orWhere( function ($q) use ($model) { - $q->where('id', $model->id); - $q->orWhere( - function ($q) use ($model) { - $q->where('accounts.name', 'LIKE', '%' . $model->name . '%'); - // TODO magic number! - $q->where('accounts.account_type_id', 3); - $q->where('accounts.active', 0); - } - ); + $q->where('accounts.name', 'LIKE', '%' . $model->name . '%'); + // TODO magic number! + $q->where('accounts.account_type_id', 3); + $q->where('accounts.active', 0); } - )->where('accounts.user_id', $this->getUser()->id); - } - )->get(); + ); + } + )->where('accounts.user_id', $this->getUser()->id); + } + )->get(); + } + )->get(); + /* + * Get all transactions. + */ + $transactions = []; + /** @var \TransactionJournal $journal */ + foreach ($journals as $journal) { + /** @var \Transaction $t */ + foreach ($journal->transactions as $t) { + $transactions[] = intval($t->id); } - )->delete(); + $journal->delete(); + } + // also delete transactions. + if (count($transactions) > 0) { + \Transaction::whereIn('id', $transactions)->delete(); + } + /* * Trigger deletion: @@ -282,8 +301,8 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface /* * Find account type. */ - /** @var \FireflyIII\Database\AccountType $acctType */ - $acctType = \App::make('FireflyIII\Database\AccountType'); + /** @var \FireflyIII\Database\AccountType\AccountType $acctType */ + $acctType = \App::make('FireflyIII\Database\AccountType\AccountType'); $accountType = $acctType->findByWhat($data['what']); @@ -321,12 +340,12 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface } /** - * @param \Eloquent $model - * @param array $data + * @param Eloquent $model + * @param array $data * * @return bool */ - public function update(\Eloquent $model, array $data) + public function update(Eloquent $model, array $data) { $model->name = $data['name']; $model->active = isset($data['active']) ? intval($data['active']) : 0; @@ -444,20 +463,19 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent */ - public function find($id) + public function find($objectId) { - return $this->getUser()->accounts()->find($id); + return $this->getUser()->accounts()->find($objectId); } /** - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * * @param $what * + * @throws NotImplementedException * @return \AccountType|null */ public function findByWhat($what) @@ -470,6 +488,7 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface * Returns all objects. * * @return Collection + * @throws NotImplementedException */ public function get() { @@ -487,10 +506,16 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface return $this->getUser()->accounts()->whereIn('id', $ids)->get(); } + /** + * @param $name + * + * @return static + * @throws \FireflyIII\Exception\FireflyException + */ public function firstExpenseAccountOrCreate($name) { - /** @var \FireflyIII\Database\AccountType $accountTypeRepos */ - $accountTypeRepos = \App::make('FireflyIII\Database\AccountType'); + /** @var \FireflyIII\Database\AccountType\AccountType $accountTypeRepos */ + $accountTypeRepos = \App::make('FireflyIII\Database\AccountType\AccountType'); $accountType = $accountTypeRepos->findByWhat('expense'); @@ -500,7 +525,7 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface // find or create cash account: return \Account::firstOrCreate( - ['name' => 'Cash account', 'account_type_id' => $cashAccountType->id, 'active' => 1, 'user_id' => $this->getUser()->id,] + ['name' => 'Cash account', 'account_type_id' => $cashAccountType->id, 'active' => 0, 'user_id' => $this->getUser()->id,] ); } @@ -510,10 +535,16 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface } + /** + * @param $name + * + * @return static + * @throws \FireflyIII\Exception\FireflyException + */ public function firstRevenueAccountOrCreate($name) { - /** @var \FireflyIII\Database\AccountType $accountTypeRepos */ - $accountTypeRepos = \App::make('FireflyIII\Database\AccountType'); + /** @var \FireflyIII\Database\AccountType\AccountType $accountTypeRepos */ + $accountTypeRepos = \App::make('FireflyIII\Database\AccountType\AccountType'); $accountType = $accountTypeRepos->findByWhat('revenue'); @@ -523,6 +554,12 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface } + /** + * @param \Account $account + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getAllTransactionJournals(\Account $account, $limit = 50) { $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; @@ -568,6 +605,13 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface return $date; } + /** + * @param \Account $account + * @param int $limit + * @param string $range + * + * @return \Illuminate\Pagination\Paginator + */ public function getTransactionJournals(\Account $account, $limit = 50, $range = 'session') { $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; @@ -580,8 +624,8 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface ->orderBy('date', 'DESC'); if ($range == 'session') { - $query->before(\Session::get('end')); - $query->after(\Session::get('start')); + $query->before(\Session::get('end', Carbon::now()->startOfMonth())); + $query->after(\Session::get('start', Carbon::now()->startOfMonth())); } $count = $query->count(); $set = $query->take($limit)->offset($offset)->get(['transaction_journals.*']); diff --git a/app/lib/FireflyIII/Database/Ifaces/AccountInterface.php b/app/lib/FireflyIII/Database/Account/AccountInterface.php similarity index 97% rename from app/lib/FireflyIII/Database/Ifaces/AccountInterface.php rename to app/lib/FireflyIII/Database/Account/AccountInterface.php index 614c476556..55c7883865 100644 --- a/app/lib/FireflyIII/Database/Ifaces/AccountInterface.php +++ b/app/lib/FireflyIII/Database/Account/AccountInterface.php @@ -1,6 +1,6 @@ delete(); @@ -42,17 +44,15 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface * @param array $data * * @return \Eloquent + * @throws FireflyException */ public function store(array $data) { - $data['user_id'] = $this->getUser()->id; - - $budget = new \Budget($data); - $budget->class = 'Budget'; + $budget = new \Budget($data); if (!$budget->isValid()) { - var_dump($budget->getErrors()->all()); - exit; + \Log::error('Could not store budget: ' . $budget->getErrors()->toJson()); + throw new FireflyException($budget->getErrors()->first()); } $budget->save(); @@ -60,20 +60,14 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface } /** - * @param \Eloquent $model - * @param array $data + * @param Eloquent $model + * @param array $data * * @return bool */ - public function update(\Eloquent $model, array $data) + public function update(Eloquent $model, array $data) { $model->name = $data['name']; - if (!$model->isValid()) { - var_dump($model->getErrors()->all()); - exit; - } - - $model->save(); return true; @@ -91,25 +85,9 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface { $warnings = new MessageBag; $successes = new MessageBag; - $errors = new MessageBag; - - if (isset($model['name'])) { - if (strlen($model['name']) < 1) { - $errors->add('name', 'Name is too short'); - } - if (strlen($model['name']) > 200) { - $errors->add('name', 'Name is too long'); - - } - } else { - $errors->add('name', 'Name is mandatory'); - } - $validator = \Validator::make($model, \Component::$rules); - - if ($validator->invalid()) { - $errors->merge($validator->errors()); - } - + $budget = new \Budget($model); + $budget->isValid(); + $errors = $budget->getErrors(); if (!$errors->has('name')) { $successes->add('name', 'OK'); @@ -121,13 +99,13 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent */ - public function find($id) + public function find($objectId) { - return $this->getUser()->budgets()->find($id); + return $this->getUser()->budgets()->find($objectId); } /** @@ -136,6 +114,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface * @param $what * * @return \AccountType|null + * @throws NotImplementedException */ public function findByWhat($what) { @@ -159,6 +138,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface * @param array $ids * * @return Collection + * @throws NotImplementedException */ public function getByIds(array $ids) { @@ -166,6 +146,57 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface throw new NotImplementedException; } + /** + * Returns all the transaction journals for a limit, possibly limited by a limit repetition. + * + * @param \Budget $budget + * @param \LimitRepetition $repetition + * @param int $take + * + * @return \Illuminate\Pagination\Paginator + */ + public function getJournals(\Budget $budget, \LimitRepetition $repetition = null, $take = 50) + { + $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $take : 0; + + + $setQuery = $budget->transactionJournals()->withRelevantData()->take($take)->offset($offset)->orderBy('date', 'DESC'); + $countQuery = $budget->transactionJournals(); + + + if (!is_null($repetition)) { + $setQuery->after($repetition->startdate)->before($repetition->enddate); + $countQuery->after($repetition->startdate)->before($repetition->enddate); + } + + + $set = $setQuery->get(['transaction_journals.*']); + $count = $countQuery->count(); + $items = []; + foreach ($set as $entry) { + $items[] = $entry; + } + + return \Paginator::make($items, $count, $take); + } + + /** + * @param \Budget $budget + * @param Carbon $date + * + * @return \LimitRepetition + */ + public function getRepetitionByDate(\Budget $budget, Carbon $date) + { + return $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']); + } + + /** + * @param \Budget $budget + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getTransactionJournals(\Budget $budget, $limit = 50) { $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; @@ -180,6 +211,13 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface } + /** + * @param \Budget $budget + * @param \LimitRepetition $repetition + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getTransactionJournalsInRepetition(\Budget $budget, \LimitRepetition $repetition, $limit = 50) { $start = $repetition->startdate; @@ -199,6 +237,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface } /** + * This method includes the time because otherwise, SQLite doesn't understand it. * @param \Budget $budget * @param Carbon $date * @@ -207,11 +246,10 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface public function repetitionOnStartingOnDate(\Budget $budget, Carbon $date) { return \LimitRepetition:: - leftJoin('limits', 'limit_repetitions.limit_id', '=', 'limits.id')->leftJoin( - 'components', 'limits.component_id', '=', 'components.id' - )->where('limit_repetitions.startdate', $date->format('Y-m-d'))->where( - 'components.id', $budget->id - )->first(['limit_repetitions.*']); + leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->where('limit_repetitions.startdate', $date->format('Y-m-d 00:00:00')) + ->where('budget_limits.budget_id', $budget->id) + ->first(['limit_repetitions.*']); } /** @@ -223,15 +261,23 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface public function transactionsWithoutBudgetInDateRange(Carbon $start, Carbon $end) { // Add expenses that have no budget: - return $this->getUser()->transactionjournals()->whereNotIn( - 'transaction_journals.id', function ($query) use ($start, $end) { - $query->select('transaction_journals.id')->from('transaction_journals')->leftJoin( - 'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id' - )->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')->where( - 'transaction_journals.date', '>=', $start->format('Y-m-d') - )->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->where('components.class', 'Budget'); - } - )->before($end)->after($start)->lessThan(0)->transactionTypes(['Withdrawal'])->get(); + return $this->getUser() + ->transactionjournals() + ->whereNotIn( + 'transaction_journals.id', function ($query) use ($start, $end) { + $query + ->select('transaction_journals.id') + ->from('transaction_journals') + ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')); + } + ) + ->before($end) + ->after($start) + ->lessThan(0) + ->transactionTypes(['Withdrawal']) + ->get(); } /** @@ -265,11 +311,14 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface } /** + * This method updates the amount (envelope) for the given date and budget. This results in a (new) limit (aka an envelope) + * for that budget. Returned to the user is the new limit repetition. + * * @param \Budget $budget * @param Carbon $date * @param $amount * - * @return \Limit + * @return \LimitRepetition * @throws \Exception */ public function updateLimitAmount(\Budget $budget, Carbon $date, $amount) @@ -278,13 +327,15 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface $limit = $this->limitOnStartingOnDate($budget, $date); if (!$limit) { // create one! - $limit = new \Limit; + $limit = new \BudgetLimit; $limit->budget()->associate($budget); - $limit->startdate = $date; - $limit->amount = $amount; + $limit->startdate = $date; + $limit->amount = $amount; $limit->repeat_freq = 'monthly'; - $limit->repeats = 0; - $limit->save(); + $limit->repeats = 0; + $result = $limit->save(); + \Log::info('Created new limit? ' . boolstr($result)); + \Log::info('ID: ' . $limit->id); /* * A newly stored limit also created a limit repetition. */ @@ -302,7 +353,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface } } - return $limit; + return $limit->limitrepetitions()->first(); } @@ -315,6 +366,6 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface */ public function limitOnStartingOnDate(\Budget $budget, Carbon $date) { - return $budget->limits()->where('startdate', $date->format('Y-m-d'))->first(); + return $budget->budgetLimits()->where('startdate', $date->format('Y-m-d'))->first(); } } \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Ifaces/BudgetInterface.php b/app/lib/FireflyIII/Database/Budget/BudgetInterface.php similarity index 93% rename from app/lib/FireflyIII/Database/Ifaces/BudgetInterface.php rename to app/lib/FireflyIII/Database/Budget/BudgetInterface.php index 149970cbc2..1e1dc36de0 100644 --- a/app/lib/FireflyIII/Database/Ifaces/BudgetInterface.php +++ b/app/lib/FireflyIII/Database/Budget/BudgetInterface.php @@ -1,6 +1,6 @@ delete(); @@ -43,16 +44,16 @@ class Category implements CUD, CommonDatabaseCalls * @param array $data * * @return \Eloquent + * @throws FireflyException */ public function store(array $data) { - $category = new \Category; - $category->name = $data['name']; - $category->class = 'Category'; + $category = new \Category; + $category->name = $data['name']; $category->user()->associate($this->getUser()); if (!$category->isValid()) { - var_dump($category->getErrors()); - exit(); + \Log::error('Could not store category: ' . $category->getErrors()->toJson()); + throw new FireflyException($category->getErrors()->first()); } $category->save(); @@ -60,20 +61,15 @@ class Category implements CUD, CommonDatabaseCalls } /** - * @param \Eloquent $model - * @param array $data + * @param Eloquent $model + * @param array $data * * @return bool + * @throws FireflyException */ - public function update(\Eloquent $model, array $data) + public function update(Eloquent $model, array $data) { $model->name = $data['name']; - if (!$model->isValid()) { - var_dump($model->getErrors()->all()); - exit; - } - - $model->save(); return true; @@ -91,25 +87,9 @@ class Category implements CUD, CommonDatabaseCalls { $warnings = new MessageBag; $successes = new MessageBag; - $errors = new MessageBag; - - if (isset($model['name'])) { - if (strlen($model['name']) < 1) { - $errors->add('name', 'Name is too short'); - } - if (strlen($model['name']) > 200) { - $errors->add('name', 'Name is too long'); - - } - } else { - $errors->add('name', 'Name is mandatory'); - } - $validator = \Validator::make($model, \Component::$rules); - - if ($validator->invalid()) { - $errors->merge($validator->getErrors()); - } - + $category = new \Category($model); + $category->isValid(); + $errors = $category->getErrors(); if (!$errors->has('name')) { $successes->add('name', 'OK'); @@ -121,11 +101,12 @@ class Category implements CUD, CommonDatabaseCalls /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent + * @throws NotImplementedException */ - public function find($id) + public function find($objectId) { // TODO: Implement find() method. throw new NotImplementedException; @@ -137,6 +118,7 @@ class Category implements CUD, CommonDatabaseCalls * @param $what * * @return \AccountType|null + * @throws NotImplementedException */ public function findByWhat($what) { @@ -158,6 +140,7 @@ class Category implements CUD, CommonDatabaseCalls * @param array $ids * * @return Collection + * @throws NotImplementedException */ public function getByIds(array $ids) { @@ -165,11 +148,22 @@ class Category implements CUD, CommonDatabaseCalls throw new NotImplementedException; } + /** + * @param $name + * + * @return \Category + */ public function firstOrCreate($name) { return \Category::firstOrCreate(['user_id' => $this->getUser()->id, 'name' => $name]); } + /** + * @param \Category $category + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getTransactionJournals(\Category $category, $limit = 50) { $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; @@ -185,14 +179,16 @@ class Category implements CUD, CommonDatabaseCalls } /** - * @param \Category $budget + * @param \Category $category * @param Carbon $date * * @return null + * @throws NotImplementedException + * @internal param \Category $budget */ public function repetitionOnStartingOnDate(\Category $category, Carbon $date) { - return null; + throw new NotImplementedException; } /** diff --git a/app/lib/FireflyIII/Database/Ifaces/CommonDatabaseCalls.php b/app/lib/FireflyIII/Database/CommonDatabaseCalls.php similarity index 77% rename from app/lib/FireflyIII/Database/Ifaces/CommonDatabaseCalls.php rename to app/lib/FireflyIII/Database/CommonDatabaseCalls.php index 2c47a6023c..ba3bf5d6c7 100644 --- a/app/lib/FireflyIII/Database/Ifaces/CommonDatabaseCalls.php +++ b/app/lib/FireflyIII/Database/CommonDatabaseCalls.php @@ -1,11 +1,10 @@ delete(); } @@ -42,59 +42,42 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface * @param array $data * * @return \Eloquent + * @throws FireflyException */ public function store(array $data) { - $data['rep_every'] = isset($data['rep_every']) ? $data['rep_every'] : 0; - $data['reminder_skip'] = isset($data['reminder_skip']) ? $data['reminder_skip'] : 0; - $data['order'] = isset($data['order']) ? $data['order'] : 0; - $data['remind_me'] = isset($data['remind_me']) ? intval($data['remind_me']) : 0; - $data['startdate'] = isset($data['startdate']) ? $data['startdate'] : Carbon::now()->format('Y-m-d'); - $data['targetdate'] = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null; - - if ($data['remind_me'] == 0) { + if (!isset($data['remind_me']) || (isset($data['remind_me']) && $data['remind_me'] == 0)) { $data['reminder'] = null; } + $piggyBank = new \Piggybank($data); + $piggyBank->save(); - - $piggybank = new \Piggybank($data); - if (!$piggybank->isValid()) { - var_dump($piggybank->getErrors()->all()); - exit; - } - $piggybank->save(); - - return $piggybank; + return $piggyBank; } /** - * @param \Eloquent $model - * @param array $data + * @param Eloquent $model + * @param array $data * * @return bool */ - public function update(\Eloquent $model, array $data) + public function update(Eloquent $model, array $data) { /** @var \Piggybank $model */ $model->name = $data['name']; $model->account_id = intval($data['account_id']); $model->targetamount = floatval($data['targetamount']); $model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null; - $model->rep_every = isset($data['rep_every']) ? $data['rep_every'] : 0; - $model->reminder_skip = isset($data['reminder_skip']) ? $data['reminder_skip'] : 0; - $model->order = isset($data['order']) ? $data['order'] : 0; - $model->remind_me = isset($data['remind_me']) ? intval($data['remind_me']) : 0; + $model->rep_every = intval($data['rep_every']); + $model->reminder_skip = intval($data['reminder_skip']); + $model->order = intval($data['order']); + $model->remind_me = intval($data['remind_me']); $model->reminder = isset($data['reminder']) ? $data['reminder'] : 'month'; if ($model->remind_me == 0) { $model->reminder = null; } - if (!$model->isValid()) { - var_dump($model->getErrors()); - exit(); - } - $model->save(); return true; @@ -104,6 +87,8 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface * Validates an array. Returns an array containing MessageBags * errors/warnings/successes. * + * Ignore PHPMD rules because Laravel 5.0 will make this method superfluous anyway. + * * @param array $model * * @return array @@ -186,14 +171,16 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent */ - public function find($id) + public function find($objectId) { return \Piggybank:: - leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where('piggybanks.id', '=', $id)->where('accounts.user_id', $this->getUser()->id) + leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where('piggybanks.id', '=', $objectId)->where( + 'accounts.user_id', $this->getUser()->id + ) ->first(['piggybanks.*']); } @@ -203,6 +190,7 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface * @param $what * * @return \AccountType|null + * @throws NotImplementedException */ public function findByWhat($what) { @@ -224,6 +212,7 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface * @param array $ids * * @return Collection + * @throws NotImplementedException */ public function getByIds(array $ids) { @@ -231,8 +220,17 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface throw new NotImplementedException; } + /** + * @param \Piggybank $piggybank + * @param Carbon $date + * + * @return mixed + * @throws FireflyException + * @throws NotImplementedException + */ public function findRepetitionByDate(\Piggybank $piggybank, Carbon $date) { + /** @var Collection $reps */ $reps = $piggybank->piggybankrepetitions()->get(); if ($reps->count() == 1) { return $reps->first(); @@ -240,7 +238,21 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface if ($reps->count() == 0) { throw new FireflyException('Should always find a piggy bank repetition.'); } - throw new NotImplementedException; + // should filter the one we need: + $repetitions = $reps->filter( + function (\PiggybankRepetition $rep) use ($date) { + if ($date >= $rep->startdate && $date <= $rep->targetdate) { + return $rep; + } + + return null; + } + ); + if ($repetitions->count() == 0) { + return null; + } + + return $repetitions->first(); } /** @@ -250,7 +262,9 @@ class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface */ public function leftOnAccount(\Account $account) { + \Log::debug('Now in leftOnAccount() for account #'.$account->id.' ('.$account->name.')'); $balance = \Steam::balance($account); + \Log::debug('Steam says: ' . $balance); /** @var \Piggybank $p */ foreach ($account->piggybanks()->get() as $p) { $balance -= $p->currentRelevantRep()->currentamount; diff --git a/app/lib/FireflyIII/Database/Ifaces/PiggybankInterface.php b/app/lib/FireflyIII/Database/PiggyBank/PiggybankInterface.php similarity index 64% rename from app/lib/FireflyIII/Database/Ifaces/PiggybankInterface.php rename to app/lib/FireflyIII/Database/PiggyBank/PiggybankInterface.php index 65af492523..dbcbea2635 100644 --- a/app/lib/FireflyIII/Database/Ifaces/PiggybankInterface.php +++ b/app/lib/FireflyIII/Database/PiggyBank/PiggybankInterface.php @@ -1,13 +1,13 @@ setUser(\Auth::user()); + } + + /** + * Based on the piggy bank, the reminder-setting and + * other variables this method tries to divide the piggy bank into equal parts. Each is + * accommodated by a reminder (if everything goes to plan). + * + * @param \PiggybankRepetition $repetition + * + * @return Collection + */ + public function calculateParts(\PiggybankRepetition $repetition) + { + /** @var \Piggybank $piggyBank */ + $piggyBank = $repetition->piggybank()->first(); + $bars = new Collection; + $currentStart = clone $repetition->startdate; + + if (is_null($piggyBank->reminder)) { + $entry = ['repetition' => $repetition, 'amountPerBar' => floatval($piggyBank->targetamount), + 'currentAmount' => floatval($repetition->currentamount), 'cumulativeAmount' => floatval($piggyBank->targetamount), + 'startDate' => clone $repetition->startdate, 'targetDate' => clone $repetition->targetdate]; + $bars->push($this->createPiggyBankPart($entry)); + + return $bars; + } + + while ($currentStart < $repetition->targetdate) { + $currentTarget = \DateKit::endOfX($currentStart, $piggyBank->reminder, $repetition->targetdate); + $entry = ['repetition' => $repetition, 'amountPerBar' => null, 'currentAmount' => floatval($repetition->currentamount), + 'cumulativeAmount' => null, 'startDate' => $currentStart, 'targetDate' => $currentTarget]; + $bars->push($this->createPiggyBankPart($entry)); + $currentStart = clone $currentTarget; + $currentStart->addDay(); + + } + $amountPerBar = floatval($piggyBank->targetamount) / $bars->count(); + $cumulative = $amountPerBar; + /** @var PiggybankPart $bar */ + foreach ($bars as $index => $bar) { + $bar->setAmountPerBar($amountPerBar); + $bar->setCumulativeAmount($cumulative); + if ($bars->count() - 1 == $index) { + $bar->setCumulativeAmount($piggyBank->targetamount); + } + $cumulative += $amountPerBar; + } + + return $bars; + } + + /** + * @param array $data + * + * @return PiggybankPart + */ + public function createPiggyBankPart(array $data) + { + $part = new PiggybankPart; + $part->setRepetition($data['repetition']); + $part->setAmountPerBar($data['amountPerBar']); + $part->setCurrentamount($data['currentAmount']); + $part->setCumulativeAmount($data['cumulativeAmount']); + $part->setStartdate($data['startDate']); + $part->setTargetdate($data['targetDate']); + + return $part; + } + + /** + * @param Eloquent $model + * + * @return bool + * @throws NotImplementedException + */ + public function destroy(Eloquent $model) + { + // TODO: Implement destroy() method. + throw new NotImplementedException; + } + + /** + * @param array $data + * + * @return \Eloquent + */ + public function store(array $data) + { + + $data['rep_every'] = intval($data['rep_every']); + $data['reminder_skip'] = intval($data['reminder_skip']); + $data['order'] = intval($data['order']); + $data['remind_me'] = intval($data['remind_me']); + $data['account_id'] = intval($data['account_id']); + + + if ($data['remind_me'] == 0) { + $data['reminder'] = null; + } + + $repeated = new \Piggybank($data); + $repeated->save(); + + return $repeated; + } + + /** + * @param Eloquent $model + * @param array $data + * + * @return bool + * @throws NotImplementedException + */ + public function update(Eloquent $model, array $data) + { + // TODO: Implement update() method. + throw new NotImplementedException; + } + + /** + * Validates an array. Returns an array containing MessageBags + * errors/warnings/successes. + * + * + * ignored because this method will be gone soon. + * + * @param array $model + * + * @return array + */ + public function validate(array $model) + { + $warnings = new MessageBag; + $successes = new MessageBag; + $errors = new MessageBag; + + /* + * Name validation: + */ + if (!isset($model['name'])) { + $errors->add('name', 'Name is mandatory'); + } + + if (isset($model['name']) && strlen($model['name']) == 0) { + $errors->add('name', 'Name is too short'); + } + if (isset($model['name']) && strlen($model['name']) > 100) { + $errors->add('name', 'Name is too long'); + } + + if (intval($model['account_id']) == 0) { + $errors->add('account_id', 'Account is mandatory'); + } + if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) { + $errors->add('targetdate', 'Target date is mandatory when setting reminders.'); + } + if ($model['targetdate'] != '') { + try { + new Carbon($model['targetdate']); + } catch (\Exception $e) { + $errors->add('targetdate', 'Invalid date.'); + } + $diff = Carbon::now()->diff(new Carbon($model['targetdate'])); + if ($diff->days > 365) { + $errors->add('targetdate', 'First target date should a a year or less from now.'); + } + } else { + $errors->add('targetdate', 'Invalid target date.'); + } + if (floatval($model['targetamount']) < 0.01) { + $errors->add('targetamount', 'Amount should be above 0.01.'); + } + if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggybank_periods'))) { + $errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')'); + } + + if (!in_array(ucfirst($model['rep_length']), \Config::get('firefly.piggybank_periods'))) { + $errors->add('rep_length', 'Invalid repeat period (' . $model['rep_length'] . ')'); + } + + // check period. + if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) { + $today = new Carbon; + $target = new Carbon($model['targetdate']); + switch ($model['reminder']) { + case 'week': + $today->addWeek(); + break; + case 'month': + $today->addMonth(); + break; + case 'year': + $today->addYear(); + break; + } + if ($today > $target) { + $errors->add('reminder', 'Target date is too close to today to set reminders.'); + } + } + + $validator = \Validator::make($model, \Piggybank::$rules); + if ($validator->invalid()) { + $errors->merge($errors); + } + + // add ok messages. + $list = ['name', 'account_id', 'rep_every', 'rep_times', 'rep_length', 'targetamount', 'targetdate', 'remind_me', 'reminder']; + foreach ($list as $entry) { + if (!$errors->has($entry) && !$warnings->has($entry)) { + $successes->add($entry, 'OK'); + } + } + + return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; + } + + /** + * Returns an object with id $id. + * + * @param int $objectId + * + * @return \Eloquent + * @throws NotImplementedException + */ + public function find($objectId) + { + // TODO: Implement find() method. + throw new NotImplementedException; + } + + /** + * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. + * + * @param $what + * + * @return \AccountType|null + * @throws NotImplementedException + */ + public function findByWhat($what) + { + // TODO: Implement findByWhat() method. + throw new NotImplementedException; + } + + /** + * Returns all objects. + * + * @return Collection + */ + public function get() + { + return $this->getUser()->piggybanks()->where('repeats', 1)->get(); + } + + /** + * @param array $ids + * + * @return Collection + * @throws NotImplementedException + */ + public function getByIds(array $ids) + { + // TODO: Implement getByIds() method. + throw new NotImplementedException; + } + + /** + * @param \Account $account + * + * @return float + * @throws NotImplementedException + */ + public function leftOnAccount(\Account $account) + { + // TODO: Implement leftOnAccount() method. + throw new NotImplementedException; + } +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Recurring.php b/app/lib/FireflyIII/Database/RecurringTransaction/RecurringTransaction.php similarity index 73% rename from app/lib/FireflyIII/Database/Recurring.php rename to app/lib/FireflyIII/Database/RecurringTransaction/RecurringTransaction.php index d87a7f2b33..1a4b424043 100644 --- a/app/lib/FireflyIII/Database/Recurring.php +++ b/app/lib/FireflyIII/Database/RecurringTransaction/RecurringTransaction.php @@ -1,24 +1,23 @@ delete(); @@ -49,7 +48,6 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface */ public function store(array $data) { - var_dump($data); $recurring = new \RecurringTransaction; $recurring->user()->associate($this->getUser()); $recurring->name = $data['name']; @@ -60,37 +58,30 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface $date = new Carbon($data['date']); - $recurring->active = isset($data['active']) && intval($data['active']) == 1 ? 1 : 0; - $recurring->automatch = isset($data['automatch']) && intval($data['automatch']) == 1 ? 1 : 0; + $recurring->active = intval($data['active']); + $recurring->automatch = intval($data['automatch']); $recurring->repeat_freq = $data['repeat_freq']; /* * Jump to the start of the period. */ - $date = DateKit::startOfPeriod($date, $data['repeat_freq']); + $date = \DateKit::startOfPeriod($date, $data['repeat_freq']); $recurring->date = $date; $recurring->skip = intval($data['skip']); - if (!$recurring->isValid()) { - var_dump($recurring->getErrors()); - exit(); - } - $recurring->save(); return $recurring; } /** - * @param \Eloquent $model - * @param array $data + * @param Eloquent $model + * @param array $data * * @return bool */ - public function update(\Eloquent $model, array $data) + public function update(Eloquent $model, array $data) { - var_dump($data); - $model->name = $data['name']; $model->match = $data['match']; $model->amount_max = floatval($data['amount_max']); @@ -99,16 +90,10 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface $date = new Carbon($data['date']); $model->date = $date; - $model->active = isset($data['active']) && intval($data['active']) == 1 ? 1 : 0; - $model->automatch = isset($data['automatch']) && intval($data['automatch']) == 1 ? 1 : 0; + $model->active = intval($data['active']); + $model->automatch = intval($data['automatch']); $model->repeat_freq = $data['repeat_freq']; $model->skip = intval($data['skip']); - - if (!$model->isValid()) { - var_dump($model->getErrors()); - exit(); - } - $model->save(); return true; @@ -118,6 +103,8 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface * Validates an array. Returns an array containing MessageBags * errors/warnings/successes. * + * ignored because this method will be gone soon. + * * @param array $model * * @return array @@ -127,45 +114,13 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface $warnings = new MessageBag; $successes = new MessageBag; $errors = new MessageBag; - - if (isset($model['name']) && strlen($model['name']) == 0) { - $errors->add('name', 'Name must be longer.'); - } - if (isset($model['name']) && strlen($model['name']) > 200) { - $errors->add('name', 'Name must be shorter.'); - } - - if (isset($model['match']) && strlen(trim($model['match'])) <= 2) { - $errors->add('match', 'Needs more matches.'); - } - - if (isset($model['amount_min']) && floatval($model['amount_min']) < 0.01) { - $errors->add('amount_min', 'Minimum amount must be higher.'); - } - if (isset($model['amount_max']) && floatval($model['amount_max']) < 0.02) { - $errors->add('amount_max', 'Maximum amount must be higher.'); - } if (isset($model['amount_min']) && isset($model['amount_max']) && floatval($model['amount_min']) > floatval($model['amount_max'])) { $errors->add('amount_max', 'Maximum amount can not be less than minimum amount.'); $errors->add('amount_min', 'Minimum amount can not be more than maximum amount.'); } - - if ($model['date'] != '') { - try { - new Carbon($model['date']); - } catch (\Exception $e) { - $errors->add('date', 'Invalid date.'); - } - } - - $reminders = \Config::get('firefly.budget_periods'); - if (!isset($model['repeat_freq']) || (isset($model['repeat_freq']) && !in_array($model['repeat_freq'], $reminders))) { - $errors->add('repeat_freq', 'Invalid reminder period'); - } - - if (isset($model['skip']) && intval($model['skip']) < 0) { - $errors->add('skip', 'Invalid skip.'); - } + $object = new \RecurringTransaction($model); + $object->isValid(); + $errors->merge($object->getErrors()); $set = ['name', 'match', 'amount_min', 'amount_max', 'date', 'repeat_freq', 'skip', 'automatch', 'active']; foreach ($set as $entry) { @@ -180,11 +135,12 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent + * @throws NotImplementedException */ - public function find($id) + public function find($objectId) { // TODO: Implement find() method. throw new NotImplementedException; @@ -196,6 +152,7 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface * @param $what * * @return \AccountType|null + * @throws NotImplementedException */ public function findByWhat($what) { @@ -217,6 +174,7 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface * @param array $ids * * @return Collection + * @throws NotImplementedException */ public function getByIds(array $ids) { @@ -224,6 +182,16 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface throw new NotImplementedException; } + /** + * Returns all objects. + * + * @return Collection + */ + public function getActive() + { + return $this->getUser()->recurringtransactions()->where('active', 1)->get(); + } + /** * @param \RecurringTransaction $recurring * @param Carbon $start @@ -320,8 +288,8 @@ class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface // get all journals that (may) be relevant. // this is usually almost all of them. - /** @var \FireflyIII\Database\TransactionJournal $journalRepository */ - $journalRepository = \App::make('FireflyIII\Database\TransactionJournal'); + /** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */ + $journalRepository = \App::make('FireflyIII\Database\TransactionJournal\TransactionJournal'); $set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $recurring->amount_min)->where('amount', '<=', $recurring->amount_max) ->get(['transaction_journal_id']); diff --git a/app/lib/FireflyIII/Database/Ifaces/RecurringInterface.php b/app/lib/FireflyIII/Database/RecurringTransaction/RecurringTransactionInterface.php similarity index 68% rename from app/lib/FireflyIII/Database/Ifaces/RecurringInterface.php rename to app/lib/FireflyIII/Database/RecurringTransaction/RecurringTransactionInterface.php index 5ff9a7aabb..da28a75b52 100644 --- a/app/lib/FireflyIII/Database/Ifaces/RecurringInterface.php +++ b/app/lib/FireflyIII/Database/RecurringTransaction/RecurringTransactionInterface.php @@ -1,6 +1,6 @@ setUser(\Auth::user()); - } - - /** - * Based on the piggy bank, the reminder-setting and - * other variables this method tries to divide the piggy bank into equal parts. Each is - * accommodated by a reminder (if everything goes to plan). - * - * @return \PiggybankRepetition - */ - public function calculateParts(\PiggybankRepetition $repetition) - { - \Log::debug('NOW in calculateParts()'); - \Log::debug('Repetition id is ' . $repetition->id); - /** @var \Piggybank $piggyBank */ - $piggyBank = $repetition->piggybank()->first(); - $bars = new Collection; - \Log::debug('connected piggy bank is: ' . $piggyBank->name . ' (#' . $piggyBank->id . ')'); - - /* - * If no reminders are set, the repetition is split in exactly one part: - */ - if (is_null($piggyBank->reminder)) { - $part = new PiggybankPart; - $part->setRepetition($repetition); - $part->setAmountPerBar(floatval($piggyBank->targetamount)); - $part->setCurrentamount($repetition->currentamount); - $part->setCumulativeAmount($piggyBank->targetamount); - $part->setStartdate(clone $repetition->startdate); - $part->setTargetdate(clone $repetition->targetdate); - $bars->push($part); - $repetition->bars = $bars; - - return $repetition; - } - $currentStart = clone $repetition->startdate; - /* - * Loop between start and target instead of counting manually. - */ - $index = 0; - //echo 'Looping!
'; - //echo $repetition->startdate . ' until ' . $repetition->targetdate . '
'; - while ($currentStart < $repetition->targetdate) { - $currentTarget = \DateKit::endOfX($currentStart, $piggyBank->reminder); - if ($currentTarget > $repetition->targetdate) { - $currentTarget = clone $repetition->targetdate; - } - - // create a part: - $part = new PiggybankPart; - $part->setRepetition($repetition); - $part->setCurrentamount($repetition->currentamount); - $part->setStartdate($currentStart); - $part->setTargetdate($currentTarget); - $bars->push($part); - //echo 'Loop #' . $index . ', from ' . $currentStart . ' until ' . $currentTarget . '
'; - - - /* - * Jump to the next period by adding a day. - */ - $currentStart = clone $currentTarget; - $currentStart->addDay();//\DateKit::addPeriod($currentTarget, $piggyBank->reminder, 0); - $index++; - - } - /* - * Loop parts again to add some - */ - $parts = $bars->count(); - $amountPerBar = floatval($piggyBank->targetamount) / $parts; - $cumulative = $amountPerBar; - /** @var PiggybankPart $bar */ - foreach ($bars as $index => $bar) { - $bar->setAmountPerBar($amountPerBar); - $bar->setCumulativeAmount($cumulative); - if($parts -1 == $index) { - $bar->setCumulativeAmount($piggyBank->targetamount); - } - - $reminder = $piggyBank->reminders() - ->where('startdate', $bar->getStartdate()->format('Y-m-d')) - ->where('enddate', $bar->getTargetdate()->format('Y-m-d')) - ->first(); - if ($reminder) { - $bar->setReminder($reminder); - } - - $cumulative += $amountPerBar; - } - - $repetition->bars = $bars; - - return $repetition; - // - // // if($parts > 12) { - // // $parts = 12; - // // $currentStart = \DateKit::startOfPeriod(Carbon::now(), $piggyBank->reminder); - // // $currentEnd = \DateKit::endOfPeriod($currentEnd, $piggyBank->reminder); - // // } - // - // for ($i = 0; $i < $parts; $i++) { - // /* - // * If it's not the first repetition, jump the start date a [period] - // * and jump the target date a [period] - // */ - // if ($i > 0) { - // $currentStart = clone $currentTarget; - // $currentStart->addDay(); - // $currentTarget = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); - // } - // /* - // * If it's the first one, and has reminders, jump to the end of the [period] - // */ - // if ($i == 0 && !is_null($piggyBank->reminder)) { - // $currentTarget = \DateKit::endOfX($currentStart, $piggyBank->reminder); - // } - // if ($currentStart > $repetition->targetdate) { - // break; - // } - // - // - // /* - // * Jump one month ahead after the first instance: - // */ - // // if ($i > 0) { - // // $currentStart = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); - // // /* - // // * Jump to the start of the period too: - // // */ - // // $currentStart = \DateKit::startOfPeriod($currentStart, $piggyBank->reminder); - // // - // // } - // - // - // /* - // * Move the current start to the actual start of - // * the [period] once the first iteration has passed. - // */ - // // if ($i != 0) { - // // $currentStart = \DateKit::startOfPeriod($currentStart, $piggyBank->reminder); - // // } - // // if($i == 0 && !is_null($piggyBank->reminder)) { - // // $currentEnd = \DateKit::startOfPeriod($currentStart, $piggyBank->reminder); - // // $currentEnd = \DateKit::endOfPeriod($currentEnd, $piggyBank->reminder); - // // } - // - // $part = new PiggybankPart; - // $part->setRepetition($repetition); - // $part->setAmount($currentAmount); - // $part->setAmountPerBar($amountPerBar); - // $part->setCurrentamount($repetition->currentamount); - // $part->setStartdate($currentStart); - // $part->setTargetdate($currentTarget); - // if (!is_null($piggyBank->reminder)) { - // // might be a reminder for this range? - // $reminder = $piggyBank->reminders() - // ->where('startdate', $currentStart->format('Y-m-d')) - // ->where('enddate', $currentTarget->format('Y-m-d')) - // ->first(); - // if ($reminder) { - // $part->setReminder($reminder); - // } - // - // } - // - // // if (!is_null($piggyBank->reminder)) { - // // $currentStart = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); - // // $currentEnd = \DateKit::endOfPeriod($currentStart, $piggyBank->reminder); - // // } - // - // - // $bars->push($part); - // $currentAmount += $amountPerBar; - // } - // $repetition->bars = $bars; - // - // return $repetition; - // exit; - // - // - // $repetition->hello = 'World!'; - // - // return $repetition; - // - // $return = new Collection; - // $repetitions = $piggyBank->piggybankrepetitions()->get(); - // /** @var \PiggybankRepetition $repetition */ - // foreach ($repetitions as $repetition) { - // - // - // if (is_null($piggyBank->reminder)) { - // // simple, one part "repetition". - // $part = new PiggybankPart; - // $part->setRepetition($repetition); - // } else { - // $part = new PiggybankPart; - // } - // - // - // // end! - // $return->push($part); - // } - // - // exit; - // - // return $return; - // $piggyBank->currentRelevantRep(); // get the current relevant repetition. - // if (!is_null($piggyBank->reminder)) { - // switch ($piggyBank->reminder) { - // default: - // throw new FireflyException('Cannot handle "' . $piggyBank->reminder . '" reminders for repeated expenses'); - // break; - // case 'month': - // $start = clone $piggyBank->currentRep->startdate; - // $start->startOfMonth(); - // $end = clone $piggyBank->currentRep->targetdate; - // $end->endOfMonth(); - // $piggyBank->parts = $start->diffInMonths($end); - // unset($start, $end); - // break; - // } - // - // } else { - // $piggyBank->parts = 1; - // } - // - // // number of bars: - // $piggyBank->barCount = floor(12 / $piggyBank->parts) == 0 ? 1 : floor(12 / $piggyBank->parts); - // $amountPerBar = floatval($piggyBank->targetamount) / $piggyBank->parts; - // $currentAmount = floatval($amountPerBar); - // $bars = []; - // $currentStart = clone $piggyBank->currentRep->startdate; - // for ($i = 0; $i < $piggyBank->parts; $i++) { - // // niet elke keer een andere dinges pakken? om target te redden? - // if (!is_null($piggyBank->reminder)) { - // $currentStart = \DateKit::addPeriod($currentStart, $piggyBank->reminder, 0); - // } - // $bars[] = [ - // 'amount' => $currentAmount, - // 'date' => $currentStart - // ]; - // - // - // $currentAmount += $amountPerBar; - // } - // $piggyBank->bars = $bars; - } - - /** - * @param \Eloquent $model - * - * @return bool - */ - public function destroy(\Eloquent $model) - { - // TODO: Implement destroy() method. - throw new NotImplementedException; - } - - /** - * @param array $data - * - * @return \Eloquent - */ - public function store(array $data) - { - - $data['rep_every'] = isset($data['rep_every']) ? $data['rep_every'] : 0; - $data['reminder_skip'] = isset($data['reminder_skip']) ? $data['reminder_skip'] : 0; - $data['order'] = isset($data['order']) ? $data['order'] : 0; - $data['remind_me'] = isset($data['remind_me']) ? intval($data['remind_me']) : 0; - $data['startdate'] = isset($data['startdate']) ? $data['startdate'] : Carbon::now()->format('Y-m-d'); - $data['targetdate'] = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null; - $data['account_id'] = intval($data['account_id']); - - - if ($data['remind_me'] == 0) { - $data['reminder'] = null; - } - - - $repeated = new \Piggybank($data); - if (!$repeated->isValid()) { - var_dump($repeated->getErrors()->all()); - exit; - } - $repeated->save(); - - return $repeated; - } - - /** - * @param \Eloquent $model - * @param array $data - * - * @return bool - */ - public function update(\Eloquent $model, array $data) - { - // TODO: Implement update() method. - throw new NotImplementedException; - } - - /** - * Validates an array. Returns an array containing MessageBags - * errors/warnings/successes. - * - * @param array $model - * - * @return array - */ - public function validate(array $model) - { - $warnings = new MessageBag; - $successes = new MessageBag; - $errors = new MessageBag; - - /* - * Name validation: - */ - if (!isset($model['name'])) { - $errors->add('name', 'Name is mandatory'); - } - - if (isset($model['name']) && strlen($model['name']) == 0) { - $errors->add('name', 'Name is too short'); - } - if (isset($model['name']) && strlen($model['name']) > 100) { - $errors->add('name', 'Name is too long'); - } - - if (intval($model['account_id']) == 0) { - $errors->add('account_id', 'Account is mandatory'); - } - if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) { - $errors->add('targetdate', 'Target date is mandatory when setting reminders.'); - } - if ($model['targetdate'] != '') { - try { - new Carbon($model['targetdate']); - } catch (\Exception $e) { - $errors->add('targetdate', 'Invalid date.'); - } - $diff = Carbon::now()->diff(new Carbon($model['targetdate'])); - if ($diff->days > 365) { - $errors->add('targetdate', 'First target date should a a year or less from now.'); - } - } else { - $errors->add('targetdate', 'Invalid target date.'); - } - if (floatval($model['targetamount']) < 0.01) { - $errors->add('targetamount', 'Amount should be above 0.01.'); - } - if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggybank_periods'))) { - $errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')'); - } - - if (!in_array(ucfirst($model['rep_length']), \Config::get('firefly.piggybank_periods'))) { - $errors->add('rep_length', 'Invalid repeat period (' . $model['rep_length'] . ')'); - } - - // check period. - if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) { - $today = new Carbon; - $target = new Carbon($model['targetdate']); - switch ($model['reminder']) { - case 'week': - $today->addWeek(); - break; - case 'month': - $today->addMonth(); - break; - case 'year': - $today->addYear(); - break; - } - if ($today > $target) { - $errors->add('reminder', 'Target date is too close to today to set reminders.'); - } - } - - $validator = \Validator::make($model, \Piggybank::$rules); - if ($validator->invalid()) { - $errors->merge($errors); - } - - // add ok messages. - $list = ['name', 'account_id', 'rep_every', 'rep_times', 'rep_length', 'targetamount', 'targetdate', 'remind_me', 'reminder']; - foreach ($list as $entry) { - if (!$errors->has($entry) && !$warnings->has($entry)) { - $successes->add($entry, 'OK'); - } - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; - } - - /** - * Returns an object with id $id. - * - * @param int $id - * - * @return \Eloquent - */ - public function find($id) - { - // TODO: Implement find() method. - throw new NotImplementedException; - } - - /** - * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. - * - * @param $what - * - * @return \AccountType|null - */ - public function findByWhat($what) - { - // TODO: Implement findByWhat() method. - throw new NotImplementedException; - } - - /** - * Returns all objects. - * - * @return Collection - */ - public function get() - { - return $this->getUser()->piggybanks()->where('repeats', 1)->get(); - } - - /** - * @param array $ids - * - * @return Collection - */ - public function getByIds(array $ids) - { - // TODO: Implement getByIds() method. - throw new NotImplementedException; - } - - /** - * @param \Account $account - * - * @return float - */ - public function leftOnAccount(\Account $account) - { - // TODO: Implement leftOnAccount() method. - throw new NotImplementedException; - } -} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Report.php b/app/lib/FireflyIII/Database/Report.php deleted file mode 100644 index 4cd5d5238c..0000000000 --- a/app/lib/FireflyIII/Database/Report.php +++ /dev/null @@ -1,175 +0,0 @@ -sharedExpense) && $account->sharedExpense === true) { - $shared = true; - } else { - if (isset($account->sharedExpense) && $account->sharedExpense === false) { - $shared = false; - } else { - $shared = ($account->getMeta('accountRole') == 'sharedExpense'); - } - } - - $start = clone $month; - $end = clone $month; - $start->startOfMonth(); - $end->endOfMonth(); - $sum = 0; - - // get all journals. - $journals = \TransactionJournal::with(['transactionType','transactions'])->whereIn( - 'id', function ($query) use ($account, $start, $end) { - $query->select('transaction_journal_id') - ->from('transactions') - ->where('account_id', $account->id); - } - )->before($end)->after($start)->get(); - - - if ($shared) { - $expenses = $journals->filter( - function (\TransactionJournal $journal) use ($account) { - // any withdrawal is an expense: - if ($journal->transactionType->type == 'Withdrawal') { - return $journal; - } - // any transfer away from this account is an expense. - if ($journal->transactionType->type == 'Transfer') { - /** @var \Transaction $t */ - foreach ($journal->transactions as $t) { - if ($t->account_id == $account->id && floatval($t->amount) < 0) { - return $journal; - } - } - } - return null; - } - ); - } else { - $expenses = $journals->filter( - function (\TransactionJournal $journal) use ($account) { - // only withdrawals are expenses: - if ($journal->transactionType->type == 'Withdrawal') { - return $journal; - } - // transfers TO a shared account are also expenses. - if ($journal->transactionType->type == 'Transfer') { - /** @var \Transaction $t */ - foreach ($journal->transactions() as $t) { - if ($t->account->getMeta('accountRole') == 'sharedExpense') { - echo '#'.$journal->id.' is a shared expense!
'; - return $journal; - } - } - } - return null; - } - ); - } - /** @var \TransactionJournal $expense */ - foreach ($expenses as $expense) { - $sum += $expense->getAmount(); - } - - - return $sum; - } - - /** - * @param \Account $account - * @param Carbon $month - * - * @return float - */ - public function getIncomeByMonth(\Account $account, Carbon $month) - { - if (isset($account->sharedExpense) && $account->sharedExpense === true) { - $shared = true; - } else { - if (isset($account->sharedExpense) && $account->sharedExpense === false) { - $shared = false; - } else { - $shared = ($account->getMeta('accountRole') == 'sharedExpense'); - } - } - - $start = clone $month; - $end = clone $month; - $start->startOfMonth(); - $end->endOfMonth(); - $sum = 0; - - // get all journals. - $journals = \TransactionJournal::with(['transactionType','transactions'])->whereIn( - 'id', function ($query) use ($account, $start, $end) { - $query->select('transaction_journal_id') - ->from('transactions') - ->where('account_id', $account->id); - } - )->before($end)->after($start)->get(); - - - if ($shared) { - $incomes = $journals->filter( - function (\TransactionJournal $journal) use ($account) { - // any deposit is an income: - if ($journal->transactionType->type == 'Deposit') { - return $journal; - } - // any transfer TO this account is an income. - if ($journal->transactionType->type == 'Transfer') { - /** @var \Transaction $t */ - foreach ($journal->transactions as $t) { - if ($t->account_id == $account->id && floatval($t->amount) > 0) { - return $journal; - } - } - } - return null; - } - ); - } else { - $incomes = $journals->filter( - function (\TransactionJournal $journal) use ($account) { - // only deposits are incomes: - if ($journal->transactionType->type == 'Deposit') { - return $journal; - } - return null; - } - ); - } - /** @var \TransactionJournal $expense */ - foreach ($incomes as $income) { - $sum += $income->getAmount(); - } - - - return $sum; - } -} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Transaction.php b/app/lib/FireflyIII/Database/Transaction/Transaction.php similarity index 51% rename from app/lib/FireflyIII/Database/Transaction.php rename to app/lib/FireflyIII/Database/Transaction/Transaction.php index 514ea66217..467ae5c9de 100644 --- a/app/lib/FireflyIII/Database/Transaction.php +++ b/app/lib/FireflyIII/Database/Transaction/Transaction.php @@ -1,16 +1,16 @@ add('account', 'No account present'); } - if (isset($model['account']) && !($model['account'] instanceof \Account)) { - $errors->add('account', 'No valid account present'); - } - if (isset($model['account_id']) && intval($model['account_id']) < 0) { - $errors->add('account', 'No valid account_id present'); + if (is_null($model['transaction_journal'])) { + $errors->add('transaction_journal', 'No valid transaction journal present'); } - if (isset($model['piggybank_id']) && intval($model['piggybank_id']) < 0) { - $errors->add('piggybank', 'No valid piggybank_id present'); - } - - if (!isset($model['transaction_journal_id']) && !isset($model['transaction_journal'])) { - $errors->add('transaction_journal', 'No TJ present'); - } - if (isset($model['transaction_journal']) && !($model['transaction_journal'] instanceof \TransactionJournal)) { - $errors->add('transaction_journal', 'No valid transaction_journal present'); - } - if (isset($model['transaction_journal_id']) && intval($model['transaction_journal_id']) < 0) { - $errors->add('account', 'No valid transaction_journal_id present'); - } - - if (isset($model['description']) && strlen($model['description']) > 255) { - $errors->add('account', 'Description too long'); - } - - if (!isset($model['amount'])) { - $errors->add('amount', 'No amount present.'); - } - if (isset($model['amount']) && floatval($model['amount']) == 0) { - $errors->add('amount', 'Invalid amount.'); - } - - if (!$errors->has('account')) { - $successes->add('account', 'OK'); - } - if (!$errors->has('')) { - $successes->add('piggybank', 'OK'); - } - if (!$errors->has('transaction_journal')) { - $successes->add('transaction_journal', 'OK'); - } - if (!$errors->has('amount')) { - $successes->add('amount', 'OK'); - } - - return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; + return $errors; } /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent + * @throws NotImplementedException */ - public function find($id) + public function find($objectId) { // TODO: Implement find() method. throw new NotImplementedException; @@ -154,6 +113,7 @@ class Transaction implements CUD, CommonDatabaseCalls * @param $what * * @return \AccountType|null + * @throws NotImplementedException */ public function findByWhat($what) { @@ -165,6 +125,7 @@ class Transaction implements CUD, CommonDatabaseCalls * Returns all objects. * * @return Collection + * @throws NotImplementedException */ public function get() { @@ -176,6 +137,7 @@ class Transaction implements CUD, CommonDatabaseCalls * @param array $ids * * @return Collection + * @throws NotImplementedException */ public function getByIds(array $ids) { diff --git a/app/lib/FireflyIII/Database/TransactionCurrency.php b/app/lib/FireflyIII/Database/TransactionCurrency.php deleted file mode 100644 index 6de3860ada..0000000000 --- a/app/lib/FireflyIII/Database/TransactionCurrency.php +++ /dev/null @@ -1,25 +0,0 @@ -first(); - } -} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php new file mode 100644 index 0000000000..887f792656 --- /dev/null +++ b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrency.php @@ -0,0 +1,149 @@ +delete(); + } + + /** + * @param array $data + * + * @return Eloquent + */ + public function store(array $data) + { + $currency = new \TransactionCurrency($data); + \Log::debug('Is valid? ' . boolstr($currency->isValid())); + $currency->save(); + + return $currency; + } + + /** + * @param Eloquent $model + * @param array $data + * + * @return bool + */ + public function update(Eloquent $model, array $data) + { + $model->symbol = $data['symbol']; + $model->code = $data['code']; + $model->name = $data['name']; + \Log::debug('Is valid? ' . boolstr($model->isValid())); + $model->save(); + + return true; + } + + /** + * Validates an array. Returns an array containing MessageBags + * errors/warnings/successes. + * + * @param array $model + * + * @return array + */ + public function validate(array $model) + { + $warnings = new MessageBag; + $successes = new MessageBag; + \Log::debug('Now in TransactionCurrency::validate()'); + + $currency = new \TransactionCurrency($model); + $currency->isValid(); + $errors = $currency->getErrors(); + + \Log::debug('Data: ' . json_encode($model)); + \Log::debug('Error-content: ' . json_encode($errors->all())); + \Log::debug('Error count is: ' . $errors->count()); + + $fields = ['name', 'code', 'symbol']; + foreach ($fields as $field) { + if (!$errors->has($field)) { + $successes->add($field, 'OK'); + } + } + + return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes]; + } + + /** + * Returns an object with id $id. + * + * @param int $objectId + * + * @return \Eloquent + */ + public function find($objectId) + { + // TODO: Implement find() method. + throw new NotImplementedException; + } + + /** + * Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc. + * + * @param $what + * + * @return \AccountType|null + */ + public function findByWhat($what) + { + // TODO: Implement findByWhat() method. + throw new NotImplementedException; + } + + /** + * Returns all objects. + * + * @return Collection + */ + public function get() + { + return \TransactionCurrency::orderBy('code', 'ASC')->get(); + } + + /** + * @param array $objectIds + * + * @return Collection + */ + public function getByIds(array $objectIds) + { + // TODO: Implement getByIds() method. + throw new NotImplementedException; + } + + /** + * @param string $code + * + * @return \TransactionCurrency|null + */ + public function findByCode($code) + { + return \TransactionCurrency::whereCode($code)->first(); + } +} \ No newline at end of file diff --git a/app/lib/FireflyIII/Database/Ifaces/TransactionCurrencyInterface.php b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrencyInterface.php similarity index 83% rename from app/lib/FireflyIII/Database/Ifaces/TransactionCurrencyInterface.php rename to app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrencyInterface.php index 1f87b9266c..e3026ca6c3 100644 --- a/app/lib/FireflyIII/Database/Ifaces/TransactionCurrencyInterface.php +++ b/app/lib/FireflyIII/Database/TransactionCurrency/TransactionCurrencyInterface.php @@ -1,6 +1,6 @@ findByWhat($data['what']); - $currency = $currencyRepository->findByCode($data['currency']); - - $journal = new \TransactionJournal; - $journal->transactionType()->associate($journalType); - $journal->transactionCurrency()->associate($currency); - $journal->user()->associate($this->getUser()); - $journal->description = $data['description']; - $journal->date = $data['date']; - $journal->completed = 0; - - /* - * This must be enough to store the journal: - */ - if (!$journal->isValid()) { - \Log::error($journal->getErrors()->all()); - throw new FireflyException('store() transaction journal failed, but it should not!'); - } + $journalType = $this->getJournalType($data['what']); + $currency = $this->getJournalCurrency($data['currency']); + $journal = new \TransactionJournal( + ['transaction_type_id' => $journalType->id, 'transaction_currency_id' => $currency->id, 'user_id' => $this->getUser()->id, + 'description' => $data['description'], 'date' => $data['date'], 'completed' => 0] + ); $journal->save(); - /* - * Still need to find the accounts related to the transactions. - * This depends on the type of transaction. - */ - switch ($data['what']) { - case 'withdrawal': - $data['from'] = $accountRepository->find($data['account_id']); - $data['to'] = $accountRepository->firstExpenseAccountOrCreate($data['expense_account']); - break; - case 'opening': - break; - case 'deposit': - $data['to'] = $accountRepository->find($data['account_id']); - $data['from'] = $accountRepository->firstRevenueAccountOrCreate($data['revenue_account']); - break; - case 'transfer': - $data['from'] = $accountRepository->find($data['account_from_id']); - $data['to'] = $accountRepository->find($data['account_to_id']); - break; + list($fromAccount, $toAccount) = $this->storeAccounts($data); - default: - throw new FireflyException('Cannot save transaction journal with accounts based on $what "' . $data['what'] . '".'); - break; - } - - /* - * Then store both transactions. - */ - $first = ['account' => $data['from'], 'transaction_journal' => $journal, 'amount' => ($data['amount'] * -1),]; - $validate = $transactionRepository->validate($first); - if ($validate['errors']->count() == 0) { - $transactionRepository->store($first); - } else { - throw new FireflyException($validate['errors']->first()); - } - - $second = ['account' => $data['to'], 'transaction_journal' => $journal, 'amount' => floatval($data['amount']),]; - - $validate = $transactionRepository->validate($second); - if ($validate['errors']->count() == 0) { - $transactionRepository->store($second); - } else { - throw new FireflyException($validate['errors']->first()); - } - - /* - * Store the budget. - */ - if (isset($data['budget_id']) && intval($data['budget_id']) > 0) { - /** @var \FireflyIII\Database\Budget $budgetRepository */ - $budgetRepository = \App::make('FireflyIII\Database\Budget'); - $budget = $budgetRepository->find(intval($data['budget_id'])); - if ($budget) { - $journal->budgets()->save($budget); - } - } - if (isset($data['category']) && strlen($data['category']) > 0) { - /** @var \FireflyIII\Database\Category $categoryRepository */ - $categoryRepository = \App::make('FireflyIII\Database\Category'); - $category = $categoryRepository->firstOrCreate($data['category']); - if ($category) { - $journal->categories()->save($category); - } - } + $this->storeTransaction(['account' => $fromAccount, 'transaction_journal' => $journal, 'amount' => floatval($data['amount'] * -1)]); + $this->storeTransaction(['account' => $toAccount, 'transaction_journal' => $journal, 'amount' => floatval($data['amount'])]); + $this->storeBudget($data, $journal); + $this->storeCategory($data, $journal); $journal->completed = 1; $journal->save(); - /* - * Trigger a search for a relevant recurring transaction. - */ - - return $journal; } /** - * @param \Eloquent $model - * @param array $data + * @param Eloquent $model + * @param array $data * * @return bool + * @throws FireflyException */ - public function update(\Eloquent $model, array $data) + public function update(Eloquent $model, array $data) { - /** @var \FireflyIII\Database\TransactionType $typeRepository */ - $typeRepository = \App::make('FireflyIII\Database\TransactionType'); - - /** @var \FireflyIII\Database\Account $accountRepository */ - $accountRepository = \App::make('FireflyIII\Database\Account'); - - /** @var \FireflyIII\Database\TransactionCurrency $currencyRepository */ - $currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency'); - - /** @var \FireflyIII\Database\Transaction $transactionRepository */ - $transactionRepository = \App::make('FireflyIII\Database\Transaction'); - - $journalType = $typeRepository->findByWhat($data['what']); - $currency = $currencyRepository->findByCode($data['currency']); + $journalType = $this->getJournalType($data['what']); + $currency = $this->getJournalCurrency($data['currency']); + $model->description = $data['description']; + $model->date = $data['date']; $model->transactionType()->associate($journalType); $model->transactionCurrency()->associate($currency); $model->user()->associate($this->getUser()); - $model->description = $data['description']; - $model->date = $data['date']; - - /* - * This must be enough to store the journal: - */ - if (!$model->isValid()) { - \Log::error($model->getErrors()->all()); - throw new FireflyException('store() transaction journal failed, but it should not!'); - } $model->save(); - /* - * Still need to find the accounts related to the transactions. - * This depends on the type of transaction. - */ - switch ($data['what']) { - case 'withdrawal': - $data['from'] = $accountRepository->find($data['account_id']); - $data['to'] = $accountRepository->firstExpenseAccountOrCreate($data['expense_account']); - break; - case 'opening': - break; - case 'deposit': - $data['to'] = $accountRepository->find($data['account_id']); - $data['from'] = $accountRepository->firstRevenueAccountOrCreate($data['revenue_account']); - break; - case 'transfer': - $data['from'] = $accountRepository->find($data['account_from_id']); - $data['to'] = $accountRepository->find($data['account_to_id']); - break; + list($fromAccount, $toAccount) = $this->storeAccounts($data); - default: - throw new FireflyException('Cannot save transaction journal with accounts based on $what "' . $data['what'] . '".'); - break; - } - - /* - * Update the budget and the category. - */ - $components = []; - if (isset($data['budget_id']) && intval($data['budget_id']) > 0) { - /** @var \FireflyIII\Database\Budget $budgetRepository */ - $budgetRepository = \App::make('FireflyIII\Database\Budget'); - $budget = $budgetRepository->find(intval($data['budget_id'])); - if ($budget) { - $components[] = $budget->id; - } - } - if (strlen($data['category']) > 0) { - /** @var \FireflyIII\Database\Category $categoryRepository */ - $categoryRepository = \App::make('FireflyIII\Database\Category'); - $category = $categoryRepository->firstOrCreate($data['category']); - if ($category) { - $components[] = $category->id; - } - } - $model->components()->sync($components); + $this->storeBudget($data, $model); + $this->storeCategory($data, $model); /* * Now we can update the transactions related to this journal. @@ -262,10 +116,10 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData foreach ($model->transactions()->get() as $transaction) { if (floatval($transaction->amount) > 0) { // the TO transaction. - $transaction->account()->associate($data['to']); + $transaction->account()->associate($toAccount); $transaction->amount = $amount; } else { - $transaction->account()->associate($data['from']); + $transaction->account()->associate($fromAccount); $transaction->amount = $amount * -1; } if (!$transaction->isValid()) { @@ -281,9 +135,12 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData * Validates an array. Returns an array containing MessageBags * errors/warnings/successes. * + * ignored because this method will be gone soon. + * * @param array $model * * @return array + * @throws FireflyException */ public function validate(array $model) { @@ -350,7 +207,6 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData /* * Many checks to catch invalid or not-existing accounts. */ - $accountError = false; switch (true) { // this combination is often seen in withdrawals. case (isset($model['account_id']) && isset($model['expense_account'])): @@ -397,27 +253,6 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData break; } - // if (isset($model['to_id']) && intval($model['to_id']) < 1) { - // $errors->add('account_to', 'Invalid to-account'); - // } - // - // if (isset($model['from_id']) && intval($model['from_id']) < 1) { - // $errors->add('account_from', 'Invalid from-account'); - // - // } - // if (isset($model['account_id']) && intval($model['account_id']) < 1) { - // $errors->add('account_id', 'Invalid account!'); - // } - // if (isset($model['to']) && !($model['to'] instanceof \Account)) { - // $errors->add('account_to', 'Invalid to-account'); - // } - // if (isset($model['from']) && !($model['from'] instanceof \Account)) { - // $errors->add('account_from', 'Invalid from-account'); - // } - // if (!isset($model['amount']) || (isset($model['amount']) && floatval($model['amount']) < 0)) { - // $errors->add('amount', 'Invalid amount'); - // } - $validator = \Validator::make([$model], \TransactionJournal::$rules); if ($validator->invalid()) { @@ -440,16 +275,133 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData } + /** + * @param $type + * + * @return \AccountType|null + * @throws FireflyException + */ + public function getJournalType($type) + { + /** @var \FireflyIII\Database\TransactionType\TransactionType $typeRepository */ + $typeRepository = \App::make('FireflyIII\Database\TransactionType\TransactionType'); + + return $typeRepository->findByWhat($type); + } + + /** + * @param $currency + * + * @return null|\TransactionCurrency + */ + public function getJournalCurrency($currency) + { + /** @var \FireflyIII\Database\TransactionCurrency\TransactionCurrency $currencyRepository */ + $currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency\TransactionCurrency'); + + return $currencyRepository->findByCode($currency); + } + + /** + * @param array $data + * + * @return array + * @throws FireflyException + */ + public function storeAccounts(array $data) + { + /** @var \FireflyIII\Database\Account\Account $accountRepository */ + $accountRepository = \App::make('FireflyIII\Database\Account\Account'); + $fromAccount = null; + $toAccount = null; + + switch ($data['what']) { + case 'withdrawal': + $fromAccount = $accountRepository->find($data['account_id']); + $toAccount = $accountRepository->firstExpenseAccountOrCreate($data['expense_account']); + break; + case 'opening': + break; + case 'deposit': + $fromAccount = $accountRepository->firstRevenueAccountOrCreate($data['revenue_account']); + $toAccount = $accountRepository->find($data['account_id']); + break; + case 'transfer': + $fromAccount = $accountRepository->find($data['account_from_id']); + $toAccount = $accountRepository->find($data['account_to_id']); + break; + + default: + throw new FireflyException('Cannot save transaction journal with accounts based on $what "' . $data['what'] . '".'); + break; + } + + return [$fromAccount, $toAccount]; + } + + /** + * @param array $data + * + * @return \Eloquent + * @throws FireflyException + */ + public function storeTransaction($data) + { + + /** @var \FireflyIII\Database\Transaction\Transaction $repository */ + $repository = \App::make('FireflyIII\Database\Transaction\Transaction'); + + $errors = $repository->validate($data); + if ($errors->count() > 0) { + \Log::error('Could not store transaction: ' . $errors->toJson()); + throw new FireflyException('store() transaction failed, but it should not!'); + } + + return $repository->store($data); + } + + /** + * @param array $data + * @param \TransactionJournal|\Eloquent $journal + */ + public function storeBudget($data, \TransactionJournal $journal) + { + if (isset($data['budget_id']) && intval($data['budget_id']) > 0) { + /** @var \FireflyIII\Database\Budget\Budget $budgetRepository */ + $budgetRepository = \App::make('FireflyIII\Database\Budget\Budget'); + $budget = $budgetRepository->find(intval($data['budget_id'])); + if ($budget) { + $journal->budgets()->sync([$budget->id]); + } + } + } + + /** + * @param array $data + * @param \TransactionJournal|\Eloquent $journal + */ + public function storeCategory(array $data, \TransactionJournal $journal) + { + if (isset($data['category']) && strlen($data['category']) > 0) { + /** @var \FireflyIII\Database\Category\Category $categoryRepository */ + $categoryRepository = \App::make('FireflyIII\Database\Category\Category'); + $category = $categoryRepository->firstOrCreate($data['category']); + if ($category) { + $journal->categories()->sync([$category->id]); + } + } + } + /** * Returns an object with id $id. * - * @param int $id + * @param int $objectId * * @return \Eloquent */ - public function find($id) + public function find($objectId) { - return $this->getUser()->transactionjournals()->find($id); + return $this->getUser()->transactionjournals()->find($objectId); } /** @@ -458,6 +410,7 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData * @param $what * * @return \AccountType|null + * @throws NotImplementedException */ public function findByWhat($what) { @@ -560,6 +513,11 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData return $sum; } + /** + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getDepositsPaginated($limit = 50) { $offset = intval(\Input::get('page')) > 0 ? (intval(\Input::get('page')) - 1) * $limit : 0; @@ -578,13 +536,13 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData /** * @param \Account $account - * @param int $count * @param Carbon $start * @param Carbon $end + * @param int $count * * @return Collection */ - public function getInDateRangeAccount(\Account $account, $count = 20, Carbon $start, Carbon $end) + public function getInDateRangeAccount(\Account $account, Carbon $start, Carbon $end, $count = 20) { $accountID = $account->id; @@ -599,6 +557,11 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData return $query; } + /** + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getTransfersPaginated($limit = 50) { $offset = intval(\Input::get('page')) > 0 ? (intval(\Input::get('page')) - 1) * $limit : 0; @@ -615,6 +578,11 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData return \Paginator::make($items, $count, $limit); } + /** + * @param int $limit + * + * @return \Illuminate\Pagination\Paginator + */ public function getWithdrawalsPaginated($limit = 50) { $offset = intval(\Input::get('page')) > 0 ? (intval(\Input::get('page')) - 1) * $limit : 0; diff --git a/app/lib/FireflyIII/Database/Ifaces/TransactionJournalInterface.php b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php similarity index 93% rename from app/lib/FireflyIII/Database/Ifaces/TransactionJournalInterface.php rename to app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php index 94ed8ec016..54635e088f 100644 --- a/app/lib/FireflyIII/Database/Ifaces/TransactionJournalInterface.php +++ b/app/lib/FireflyIII/Database/TransactionJournal/TransactionJournalInterface.php @@ -1,6 +1,6 @@ email = isset($data['email']) ? $data['email'] : null; - $user->migrated = 0; $user->reset = \Str::random(32); $user->password = \Hash::make(\Str::random(12)); diff --git a/app/lib/FireflyIII/Event/Account.php b/app/lib/FireflyIII/Event/Account.php index 7b265b9816..bdc87d8e9a 100644 --- a/app/lib/FireflyIII/Event/Account.php +++ b/app/lib/FireflyIII/Event/Account.php @@ -5,14 +5,25 @@ namespace FireflyIII\Event; use Illuminate\Events\Dispatcher; +/** + * Class Account + * + * @package FireflyIII\Event + */ class Account { + /** + * @param \Account $account + */ public function destroy(\Account $account) { \Cache::forget('account.' . $account->id . '.latestBalance'); \Cache::forget('account.' . $account->id . '.lastActivityDate'); } + /** + * @param \Account $account + */ public function store(\Account $account) { @@ -31,6 +42,9 @@ class Account $events->listen('account.destroy', 'FireflyIII\Event\Account@destroy'); } + /** + * @param \Account $account + */ public function update(\Account $account) { \Cache::forget('account.' . $account->id . '.latestBalance'); diff --git a/app/lib/FireflyIII/Event/Budget.php b/app/lib/FireflyIII/Event/Budget.php index adbd8abb95..f40e02b958 100644 --- a/app/lib/FireflyIII/Event/Budget.php +++ b/app/lib/FireflyIII/Event/Budget.php @@ -5,35 +5,40 @@ namespace FireflyIII\Event; use Illuminate\Database\QueryException; use Illuminate\Events\Dispatcher; +/** + * Class Budget + * + * @package FireflyIII\Event + */ class Budget { /** - * @param \Limit $limit + * @param \BudgetLimit $budgetLimit */ - public function storeOrUpdateLimit(\Limit $limit) + public function storeOrUpdateLimit(\BudgetLimit $budgetLimit) { - $end = \DateKit::addPeriod(clone $limit->startdate, $limit->repeat_freq, 0); + $end = \DateKit::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0); $end->subDay(); - $set = $limit->limitrepetitions()->where('startdate', $limit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))->get(); + $set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))->get(); /* * Create new LimitRepetition: */ if ($set->count() == 0) { $repetition = new \LimitRepetition(); - $repetition->startdate = $limit->startdate; + $repetition->startdate = $budgetLimit->startdate; $repetition->enddate = $end; - $repetition->amount = $limit->amount; - $repetition->limit()->associate($limit); + $repetition->amount = $budgetLimit->amount; + $repetition->budgetLimit()->associate($budgetLimit); try { $repetition->save(); } catch (QueryException $e) { - \Log::error('Trying to save new Limitrepetition failed!'); + \Log::error('Trying to save new LimitRepetition failed!'); \Log::error($e->getMessage()); } } else { @@ -42,7 +47,7 @@ class Budget * Update existing one. */ $repetition = $set->first(); - $repetition->amount = $limit->amount; + $repetition->amount = $budgetLimit->amount; $repetition->save(); } diff --git a/app/lib/FireflyIII/Event/Event.php b/app/lib/FireflyIII/Event/Event.php index 1f670ccb20..0f4bfda97a 100644 --- a/app/lib/FireflyIII/Event/Event.php +++ b/app/lib/FireflyIII/Event/Event.php @@ -4,9 +4,19 @@ namespace FireflyIII\Event; use Illuminate\Events\Dispatcher; +/** + * Class Event + * + * @package FireflyIII\Event + */ class Event { + /** + * @param \Account $account + * + * @throws \Exception + */ public function deleteAccount(\Account $account) { // get piggy banks diff --git a/app/lib/FireflyIII/Event/Piggybank.php b/app/lib/FireflyIII/Event/Piggybank.php index 05657efafb..bd9ee555f5 100644 --- a/app/lib/FireflyIII/Event/Piggybank.php +++ b/app/lib/FireflyIII/Event/Piggybank.php @@ -6,6 +6,11 @@ namespace FireflyIII\Event; use Carbon\Carbon; use Illuminate\Events\Dispatcher; +/** + * Class Piggybank + * + * @package FireflyIII\Event + */ class Piggybank { @@ -16,24 +21,30 @@ class Piggybank public function addMoney(\Piggybank $piggybank, $amount = 0.0) { if ($amount > 0) { - $event = new \PiggybankEvent; + $event = new \PiggyBankEvent; $event->piggybank()->associate($piggybank); $event->amount = floatval($amount); $event->date = new Carbon; if (!$event->isValid()) { - var_dump($event->getErrors()); - exit(); + \Log::error($event->getErrors()); + \App::abort(500); } $event->save(); } } + /** + * @param \TransactionJournal $journal + * + * @throws \FireflyIII\Exception\FireflyException + * @throws \FireflyIII\Exception\NotImplementedException + */ public function destroyTransfer(\TransactionJournal $journal) { if ($journal->piggybankevents()->count() > 0) { - /** @var \FireflyIII\Database\Piggybank $repository */ - $repository = \App::make('FireflyIII\Database\Piggybank'); + /** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */ + $repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); /** @var \Piggybank $piggyBank */ $piggyBank = $journal->piggybankevents()->first()->piggybank()->first(); @@ -56,14 +67,10 @@ class Piggybank $repetition->save(); - $event = new \PiggybankEvent; + $event = new \PiggyBankEvent; $event->piggybank()->associate($piggyBank); $event->amount = floatval($relevantTransaction->amount * -1); $event->date = new Carbon; - if (!$event->isValid()) { - var_dump($event->getErrors()); - exit(); - } $event->save(); } } @@ -76,18 +83,17 @@ class Piggybank { $amount = $amount * -1; if ($amount < 0) { - $event = new \PiggybankEvent; + $event = new \PiggyBankEvent; $event->piggybank()->associate($piggybank); $event->amount = floatval($amount); $event->date = new Carbon; - if (!$event->isValid()) { - var_dump($event->getErrors()); - exit(); - } $event->save(); } } + /** + * @param \Piggybank $piggybank + */ public function storePiggybank(\Piggybank $piggybank) { if (intval($piggybank->repeats) == 0) { @@ -110,67 +116,41 @@ class Piggybank */ public function storeTransfer(\TransactionJournal $journal, $piggybankId = 0) { - if ($piggybankId == 0 || is_null($piggybankId)) { + if (intval($piggybankId) == 0) { return; } - /** @var \FireflyIII\Database\Piggybank $repository */ - $repository = \App::make('FireflyIII\Database\Piggybank'); + /** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */ + $repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); /** @var \Piggybank $piggyBank */ $piggyBank = $repository->find($piggybankId); - /** @var \PiggybankRepetition $repetition */ - $repetition = $repository->findRepetitionByDate($piggyBank, $journal->date); - - \Log::debug( - 'Connecting transfer "' . $journal->description . '" (#' . $journal->id . ') to piggy bank "' . $piggyBank->name . '" (#' . $piggyBank->id . ').' - ); - - // some variables to double check the connection. - $start = $piggyBank->startdate; - $end = $piggyBank->targetdate; - $amount = floatval($piggyBank->targetamount); - $leftToSave = $amount - floatval($repetition->currentamount); - $relevantTransaction = null; - /** @var \Transaction $transaction */ - foreach ($journal->transactions as $transaction) { - if ($transaction->account_id == $piggyBank->account_id) { - $relevantTransaction = $transaction; - } - } - if (is_null($relevantTransaction)) { + if ($journal->transactions()->where('account_id', $piggyBank->account_id)->count() == 0) { return; } - \Log::debug('Relevant transaction is #' . $relevantTransaction->id . ' with amount ' . $relevantTransaction->amount); - - // if FF3 should save this connection depends on some variables: - if ($start && $end && $journal->date >= $start && $journal->date <= $end) { - if ($relevantTransaction->amount < 0) { // amount removed from account, so removed from piggy bank. - \Log::debug('Remove from piggy bank.'); - $continue = ($relevantTransaction->amount * -1 <= floatval($repetition->currentamount)); - \Log::debug( - 'relevantTransaction.amount *-1 = ' . ($relevantTransaction->amount * -1) . ' >= current = ' . floatval($repetition->currentamount) - ); - } else { // amount added - \Log::debug('Add from piggy bank.'); - $continue = $relevantTransaction->amount <= $leftToSave; - } - if ($continue) { - \Log::debug('Update repetition.'); - $repetition->currentamount += floatval($relevantTransaction->amount); - $repetition->save(); - - $event = new \PiggybankEvent; - $event->piggybank()->associate($piggyBank); - $event->transactionjournal()->associate($journal); - $event->amount = floatval($relevantTransaction->amount); - $event->date = new Carbon; - if (!$event->isValid()) { - var_dump($event->getErrors()); - exit(); - } - $event->save(); - } + /** @var \PiggybankRepetition $repetition */ + $repetition = $repository->findRepetitionByDate($piggyBank, $journal->date); + $amount = floatval($piggyBank->targetamount); + $leftToSave = $amount - floatval($repetition->currentamount); + $transaction = $journal->transactions()->where('account_id', $piggyBank->account_id)->first(); + // must be in range of journal. Continue determines if we can move it. + if (floatval($transaction->amount < 0)) { + // amount removed from account, so removed from piggy bank. + $continue = ($transaction->amount * -1 <= floatval($repetition->currentamount)); + } else { + // amount added + $continue = $transaction->amount <= $leftToSave; + } + if ($continue) { + \Log::debug('Update repetition.'); + $repetition->currentamount += floatval($transaction->amount); + $repetition->save(); + $event = new \PiggyBankEvent; + $event->piggybank()->associate($piggyBank); + $event->transactionjournal()->associate($journal); + $event->amount = floatval($transaction->amount); + $event->date = new Carbon; + $event->save(); } } @@ -186,7 +166,7 @@ class Piggybank $events->listen('piggybank.update', 'FireflyIII\Event\Piggybank@updatePiggybank'); \App::before( - function ($request) { + function () { $this->validateRepeatedExpenses(); } ); @@ -205,11 +185,11 @@ class Piggybank */ public function validateRepeatedExpenses() { - if(!\Auth::check()) { + if (!\Auth::check()) { return; } - /** @var \FireflyIII\Database\RepeatedExpense $repository */ - $repository = \App::make('FireflyIII\Database\RepeatedExpense'); + /** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */ + $repository = \App::make('FireflyIII\Database\PiggyBank\RepeatedExpense'); $list = $repository->get(); $today = Carbon::now(); @@ -250,6 +230,9 @@ class Piggybank } } + /** + * @param \Piggybank $piggyBank + */ public function updatePiggybank(\Piggybank $piggyBank) { // get the repetition: @@ -259,6 +242,12 @@ class Piggybank $repetition->save(); } + /** + * @param \TransactionJournal $journal + * + * @throws \FireflyIII\Exception\FireflyException + * @throws \FireflyIII\Exception\NotImplementedException + */ public function updateTransfer(\TransactionJournal $journal) { @@ -267,8 +256,8 @@ class Piggybank $event = $journal->piggybankevents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->first(); $eventSum = floatval($journal->piggybankevents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->sum('amount')); - /** @var \FireflyIII\Database\Piggybank $repository */ - $repository = \App::make('FireflyIII\Database\Piggybank'); + /** @var \FireflyIII\Database\PiggyBank\PiggyBank $repository */ + $repository = \App::make('FireflyIII\Database\PiggyBank\PiggyBank'); /** @var \Piggybank $piggyBank */ $piggyBank = $journal->piggybankevents()->first()->piggybank()->first(); @@ -295,7 +284,7 @@ class Piggybank $repetition->save(); - $event = new \PiggybankEvent; + $event = new \PiggyBankEvent; $event->piggybank()->associate($piggyBank); $event->transactionJournal()->associate($journal); $event->amount = $diff; diff --git a/app/lib/FireflyIII/Event/Transaction.php b/app/lib/FireflyIII/Event/Transaction.php index 285e942875..2b58b3c97e 100644 --- a/app/lib/FireflyIII/Event/Transaction.php +++ b/app/lib/FireflyIII/Event/Transaction.php @@ -5,14 +5,28 @@ namespace FireflyIII\Event; use Illuminate\Events\Dispatcher; +/** + * Class Transaction + * + * @package FireflyIII\Event + */ class Transaction { + /** + * @param \Transaction $transaction + */ public function destroy(\Transaction $transaction) { \Cache::forget('account.' . $transaction->account_id . '.latestBalance'); \Cache::forget('account.' . $transaction->account_id . '.lastActivityDate'); + + // delete transaction: + $transaction->delete(); } + /** + * @param \Transaction $transaction + */ public function store(\Transaction $transaction) { \Cache::forget('account.' . $transaction->account_id . '.latestBalance'); @@ -30,6 +44,9 @@ class Transaction $events->listen('transaction.destroy', 'FireflyIII\Event\Transaction@destroy'); } + /** + * @param \Transaction $transaction + */ public function update(\Transaction $transaction) { \Cache::forget('account.' . $transaction->account_id . '.latestBalance'); diff --git a/app/lib/FireflyIII/Event/TransactionJournal.php b/app/lib/FireflyIII/Event/TransactionJournal.php index aabc4c0537..ed62684c96 100644 --- a/app/lib/FireflyIII/Event/TransactionJournal.php +++ b/app/lib/FireflyIII/Event/TransactionJournal.php @@ -4,13 +4,21 @@ namespace FireflyIII\Event; use Illuminate\Events\Dispatcher; +/** + * Class TransactionJournal + * + * @package FireflyIII\Event + */ class TransactionJournal { - public function store(\TransactionJournal $journal, $id = 0) + /** + * @param \TransactionJournal $journal + */ + public function store(\TransactionJournal $journal) { - /** @var \FireflyIII\Database\Recurring $repository */ - $repository = \App::make('FireflyIII\Database\Recurring'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repository */ + $repository = \App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); $set = $repository->get(); @@ -30,10 +38,13 @@ class TransactionJournal $events->listen('transactionJournal.update', 'FireflyIII\Event\TransactionJournal@update'); } + /** + * @param \TransactionJournal $journal + */ public function update(\TransactionJournal $journal) { - /** @var \FireflyIII\Database\Recurring $repository */ - $repository = \App::make('FireflyIII\Database\Recurring'); + /** @var \FireflyIII\Database\RecurringTransaction\RecurringTransaction $repository */ + $repository = \App::make('FireflyIII\Database\RecurringTransaction\RecurringTransaction'); $set = $repository->get(); $journal->recurring_transaction_id = null; $journal->save(); diff --git a/app/lib/FireflyIII/FF3ServiceProvider.php b/app/lib/FireflyIII/FF3ServiceProvider.php index 6c86ead5b3..b79fcf3053 100644 --- a/app/lib/FireflyIII/FF3ServiceProvider.php +++ b/app/lib/FireflyIII/FF3ServiceProvider.php @@ -45,42 +45,49 @@ class FF3ServiceProvider extends ServiceProvider { // FORMAT: #$this->app->bind('Interface', 'Class'); + $this->registerFacades(); + $this->registerInterfaces(); + $this->registerAliases(); + + } + + public function registerFacades() + { $this->app->bind( 'reminders', function () { - return new Reminders; - } + return new Reminders; + } ); $this->app->bind( 'filter', function () { - return new Filter; - } + return new Filter; + } ); $this->app->bind( 'datekit', function () { - return new Date; - } + return new Date; + } ); $this->app->bind( 'navigation', function () { - return new Navigation; - } + return new Navigation; + } ); $this->app->bind( 'ffform', function () { - return new Form; - } + return new Form; + } ); - - /* - * For models, various stuff: - */ $this->app->bind( 'steam', function () { - return new Steam; - } + return new Steam; + } ); + } + public function registerInterfaces() + { // preferences: $this->app->bind('FireflyIII\Shared\Preferences\PreferencesInterface', 'FireflyIII\Shared\Preferences\Preferences'); @@ -90,7 +97,12 @@ class FF3ServiceProvider extends ServiceProvider // reports $this->app->bind('FireflyIII\Report\ReportInterface', 'FireflyIII\Report\Report'); + // chart + $this->app->bind('FireflyIII\Chart\ChartInterface', 'FireflyIII\Chart\Chart'); + } + public function registerAliases() + { // Shortcut so developers don't need to add an Alias in app/config/app.php $this->app->booting( function () { @@ -103,7 +115,6 @@ class FF3ServiceProvider extends ServiceProvider $loader->alias('Steam', 'FireflyIII\Shared\Facade\Steam'); } ); - } } \ No newline at end of file diff --git a/app/lib/FireflyIII/Form/Form.php b/app/lib/FireflyIII/Form/Form.php index 9b11b13678..13bf163944 100644 --- a/app/lib/FireflyIII/Form/Form.php +++ b/app/lib/FireflyIII/Form/Form.php @@ -123,7 +123,7 @@ class Form $html .= \Form::input('text', $name, $value, $options); break; case 'amount': - $html .= '
'; + $html .= '
'.getCurrencySymbol().'
'; $html .= \Form::input('number', $name, $value, $options); $html .= '
'; break; @@ -287,18 +287,17 @@ class Form /* * Store. */ - $store = ''; switch ($type) { case 'create': - $store = '
'; + $store = '
'; $store .= '
'; break; case 'update': - $store = '
'; + $store = '
'; $store .= '
'; break; default: @@ -309,9 +308,9 @@ class Form /* * validate is always the same: */ - $validate = '